simulationjsv2 0.5.2 → 0.7.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/graphics.js CHANGED
@@ -1,22 +1,147 @@
1
1
  import { vec3, mat4, vec2, vec4 } from 'wgpu-matrix';
2
- import { Vertex, cloneBuf, color, colorFromVector4, vector2, vector3, vertex, Color, transitionValues, vector2FromVector3, matrix4, vector3FromVector2, distance2d } from './utils.js';
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';
5
- export class SimulationElement {
2
+ import { Vertex, cloneBuf, color, colorFromVector4, vector2, vector3, vertex, Color, vector2FromVector3, matrix4, vector3FromVector2, distance2d } from './utils.js';
3
+ import { BlankGeometry, CircleGeometry, CubeGeometry, Line2dGeometry, Line3dGeometry, PlaneGeometry, PolygonGeometry, Spline2dGeometry, SquareGeometry, TraceLines2dGeometry as TraceLinesGeometry } from './geometry.js';
4
+ import { SimSceneObjInfo, VertexCache, bufferGenerator, internalTransitionValues, logger, posTo2dScreen, rotateMat4, vector3ToPixelRatio } from './internalUtils.js';
5
+ import { modelProjMatOffset } from './constants.js';
6
+ export class SimulationElement3d {
7
+ children;
8
+ uniformBuffer;
9
+ parent;
10
+ centerOffset;
11
+ rotationOffset;
12
+ pos;
6
13
  color;
7
14
  wireframe;
8
15
  vertexCache;
9
16
  rotation;
10
- isInstanced;
17
+ modelMatrix;
18
+ isInstance = false;
19
+ isInstanced = false;
20
+ is3d = true;
21
+ isEmpty = false;
11
22
  /**
12
23
  * @param pos - Expected to be adjusted to devicePixelRatio before reaching constructor
13
24
  */
14
- constructor(color = new Color(), rotation) {
25
+ constructor(pos, rotation, color = new Color()) {
26
+ this.pos = pos;
27
+ this.centerOffset = vector3();
28
+ // TODO test this
29
+ this.rotationOffset = vector3();
15
30
  this.color = color;
16
31
  this.vertexCache = new VertexCache();
17
32
  this.wireframe = false;
18
- this.rotation = rotation;
19
- this.isInstanced = false;
33
+ this.rotation = cloneBuf(rotation);
34
+ this.uniformBuffer = null;
35
+ this.children = [];
36
+ this.modelMatrix = matrix4();
37
+ this.parent = null;
38
+ }
39
+ add(el, id) {
40
+ el.setParent(this);
41
+ const info = new SimSceneObjInfo(el, id);
42
+ this.children.push(info);
43
+ }
44
+ remove(el) {
45
+ for (let i = 0; i < this.children.length; i++) {
46
+ if (this.children[i].getObj() === el) {
47
+ this.children.splice(i, 1);
48
+ }
49
+ }
50
+ }
51
+ getChildren() {
52
+ return this.children.map((child) => child.getObj());
53
+ }
54
+ getChildrenInfos() {
55
+ return this.children;
56
+ }
57
+ hasChildren() {
58
+ return this.children.length > 0;
59
+ }
60
+ setParent(parent) {
61
+ this.parent = parent;
62
+ }
63
+ getParent() {
64
+ return this.parent;
65
+ }
66
+ setCenterOffset(offset) {
67
+ this.centerOffset = offset;
68
+ }
69
+ setRotationOffset(offset) {
70
+ this.rotationOffset = offset;
71
+ }
72
+ resetCenterOffset() {
73
+ this.centerOffset[0] = 0;
74
+ this.centerOffset[1] = 0;
75
+ this.centerOffset[2] = 0;
76
+ }
77
+ propagateDevice(device) {
78
+ this.onDeviceChange(device);
79
+ for (let i = 0; i < this.children.length; i++) {
80
+ this.children[i].getObj().propagateDevice(device);
81
+ }
82
+ }
83
+ getModelMatrix() {
84
+ this.updateModelMatrix3d();
85
+ return this.modelMatrix;
86
+ }
87
+ getUniformBuffer(device, mat) {
88
+ if (!this.uniformBuffer) {
89
+ const uniformBufferSize = 4 * 16 + 4 * 16 + 4 * 2 + 8; // 4x4 matrix + 4x4 matrix + vec2<f32> + 8 bc 144 is cool
90
+ this.uniformBuffer = device.createBuffer({
91
+ size: uniformBufferSize,
92
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
93
+ });
94
+ }
95
+ device.queue.writeBuffer(this.uniformBuffer, modelProjMatOffset, mat);
96
+ return this.uniformBuffer;
97
+ }
98
+ mirrorParentTransforms3d(mat) {
99
+ if (!this.parent)
100
+ return;
101
+ this.parent.mirrorParentTransforms3d(mat);
102
+ mat4.translate(mat, this.parent.getPos(), mat);
103
+ const parentRot = this.parent.getRotation();
104
+ mat4.rotateZ(mat, parentRot[2], mat);
105
+ mat4.rotateY(mat, parentRot[1], mat);
106
+ mat4.rotateX(mat, parentRot[0], mat);
107
+ }
108
+ updateModelMatrix3d() {
109
+ mat4.identity(this.modelMatrix);
110
+ if (this.parent) {
111
+ this.mirrorParentTransforms3d(this.modelMatrix);
112
+ }
113
+ mat4.translate(this.modelMatrix, this.pos, this.modelMatrix);
114
+ // vec3.negate(this.rotationOffset, cachedVec1);
115
+ // mat4.translate(this.modelMatrix, cachedVec1, this.modelMatrix);
116
+ mat4.rotateZ(this.modelMatrix, this.rotation[2], this.modelMatrix);
117
+ mat4.rotateY(this.modelMatrix, this.rotation[1], this.modelMatrix);
118
+ mat4.rotateX(this.modelMatrix, this.rotation[0], this.modelMatrix);
119
+ // mat4.translate(this.modelMatrix, this.rotationOffset, this.modelMatrix);
120
+ mat4.translate(this.modelMatrix, this.centerOffset, this.modelMatrix);
121
+ }
122
+ mirrorParentTransforms2d(mat) {
123
+ if (!this.parent) {
124
+ const parentPos = posTo2dScreen(this.pos);
125
+ mat4.translate(mat, parentPos, mat);
126
+ return;
127
+ }
128
+ this.parent.mirrorParentTransforms2d(mat);
129
+ const parentRot = this.parent.getRotation();
130
+ mat4.rotateZ(mat, parentRot[2], mat);
131
+ mat4.translate(mat, this.pos, mat);
132
+ }
133
+ updateModelMatrix2d() {
134
+ mat4.identity(this.modelMatrix);
135
+ const pos = posTo2dScreen(this.pos);
136
+ vec3.add(pos, this.centerOffset, pos);
137
+ if (this.parent) {
138
+ this.mirrorParentTransforms2d(this.modelMatrix);
139
+ }
140
+ else {
141
+ mat4.translate(this.modelMatrix, pos, this.modelMatrix);
142
+ }
143
+ mat4.rotateZ(this.modelMatrix, this.rotation[2], this.modelMatrix);
144
+ mat4.translate(this.modelMatrix, this.centerOffset, this.modelMatrix);
20
145
  }
21
146
  getGeometryType() {
22
147
  return this.geometry.getType();
@@ -33,13 +158,22 @@ export class SimulationElement {
33
158
  getPos() {
34
159
  return this.pos;
35
160
  }
161
+ getAbsolutePos() {
162
+ const vec = vector3();
163
+ this.updateModelMatrix3d();
164
+ mat4.getTranslation(this.modelMatrix, vec);
165
+ return vec;
166
+ }
36
167
  getRotation() {
37
168
  return this.rotation;
38
169
  }
170
+ getCenterOffset() {
171
+ return this.centerOffset;
172
+ }
39
173
  fill(newColor, t = 0, f) {
40
174
  const diff = newColor.diff(this.color);
41
175
  const finalColor = newColor.clone();
42
- return transitionValues((p) => {
176
+ return internalTransitionValues((p) => {
43
177
  this.color.r += diff.r * p;
44
178
  this.color.g += diff.g * p;
45
179
  this.color.b += diff.b * p;
@@ -50,34 +184,95 @@ export class SimulationElement {
50
184
  this.vertexCache.updated();
51
185
  }, t, f);
52
186
  }
187
+ moveChildren(amount, t = 0, f) {
188
+ for (let i = 0; i < this.children.length; i++) {
189
+ this.children[i].getObj().move(amount, t, f, true);
190
+ }
191
+ }
192
+ move(amount, t = 0, f, fromDevicePixelRatio = false) {
193
+ const tempAmount = cloneBuf(amount);
194
+ if (!fromDevicePixelRatio)
195
+ vector3ToPixelRatio(tempAmount);
196
+ const finalPos = cloneBuf(this.pos);
197
+ vec3.add(finalPos, tempAmount, finalPos);
198
+ this.moveChildren(amount, t, f);
199
+ return internalTransitionValues((p) => {
200
+ this.pos[0] += tempAmount[0] * p;
201
+ this.pos[1] += tempAmount[1] * p;
202
+ this.pos[2] += tempAmount[2] * p;
203
+ }, () => {
204
+ this.pos = finalPos;
205
+ }, t, f);
206
+ }
207
+ moveTo(pos, t = 0, f, fromDevicePixelRatio = false) {
208
+ const tempPos = cloneBuf(pos);
209
+ if (!fromDevicePixelRatio)
210
+ vector3ToPixelRatio(tempPos);
211
+ const diff = vector3();
212
+ vec3.sub(tempPos, this.pos, diff);
213
+ this.moveChildren(diff, t, f);
214
+ return internalTransitionValues((p) => {
215
+ this.pos[0] += diff[0] * p;
216
+ this.pos[1] += diff[1] * p;
217
+ this.pos[2] += diff[2] * p;
218
+ }, () => {
219
+ this.pos = tempPos;
220
+ }, t, f);
221
+ }
222
+ rotateChildrenTo(angle) {
223
+ for (let i = 0; i < this.children.length; i++) {
224
+ this.children[i].getObj().rotateTo(angle);
225
+ }
226
+ }
227
+ rotateChildren(angle) {
228
+ for (let i = 0; i < this.children.length; i++) {
229
+ this.children[i].getObj().rotate(angle);
230
+ }
231
+ }
232
+ rotate(amount, t = 0, f) {
233
+ const finalRotation = cloneBuf(amount);
234
+ vec3.add(finalRotation, this.rotation, finalRotation);
235
+ const tempDiff = vector3();
236
+ return internalTransitionValues((p) => {
237
+ vec3.scale(amount, p, tempDiff);
238
+ this.rotation[0] += tempDiff[0];
239
+ this.rotation[1] += tempDiff[1];
240
+ this.rotation[2] += tempDiff[2];
241
+ }, () => {
242
+ this.rotation = finalRotation;
243
+ }, t, f);
244
+ }
245
+ rotateTo(rot, t = 0, f) {
246
+ const diff = vec3.sub(rot, this.rotation);
247
+ const tempDiff = vector3();
248
+ return internalTransitionValues((p) => {
249
+ vec3.scale(diff, p, tempDiff);
250
+ this.rotation[0] += tempDiff[0];
251
+ this.rotation[1] += tempDiff[1];
252
+ this.rotation[2] += tempDiff[2];
253
+ }, () => {
254
+ this.rotation = cloneBuf(rot);
255
+ }, t, f);
256
+ }
53
257
  getVertexCount() {
54
258
  if (this.vertexCache.shouldUpdate()) {
55
259
  this.geometry.recompute();
56
260
  }
57
- if (this.isWireframe()) {
58
- return this.geometry.getWireframeVertexCount();
261
+ let childrenVertices = 0;
262
+ for (let i = 0; i < this.children.length; i++) {
263
+ childrenVertices += this.children[i].getObj().getVertexCount();
59
264
  }
60
- return this.geometry.getTriangleVertexCount();
61
- }
62
- defaultUpdateMatrix(camera) {
63
- const matrix = matrix4();
64
- if (typeof this.rotation === 'number') {
65
- const pos = vector3FromVector2(this.pos);
66
- pos[1] = camera.getScreenSize()[1] + pos[1];
67
- mat4.translate(matrix, pos, matrix);
68
- mat4.rotateZ(matrix, this.rotation, matrix);
265
+ let currentVertices = 0;
266
+ if (this.isWireframe()) {
267
+ currentVertices = this.geometry.getWireframeVertexCount();
69
268
  }
70
269
  else {
71
- mat4.translate(matrix, this.pos, matrix);
72
- rotateMat4(matrix, this.rotation);
270
+ currentVertices = this.geometry.getTriangleVertexCount();
73
271
  }
74
- this.geometry.updateMatrix(matrix);
272
+ return currentVertices + childrenVertices;
75
273
  }
76
- getBuffer(camera, vertexParamGenerator) {
77
- const shouldEvalExtender = vertexParamGenerator?.shouldEvaluate?.();
78
- const reEvalExtender = shouldEvalExtender === undefined ? true : shouldEvalExtender;
79
- if (this.vertexCache.shouldUpdate() || camera.hasUpdated() || reEvalExtender) {
80
- this.updateMatrix(camera);
274
+ getBuffer(vertexParamGenerator) {
275
+ if (this.vertexCache.shouldUpdate()) {
81
276
  this.geometry.recompute();
82
277
  if (this.isInstanced) {
83
278
  bufferGenerator.setInstancing(true);
@@ -96,124 +291,35 @@ export class SimulationElement {
96
291
  return this.vertexCache.getCache();
97
292
  }
98
293
  }
99
- export class SimulationElement3d extends SimulationElement {
100
- pos;
101
- rotation;
102
- is3d = true;
103
- constructor(pos, rotation = vector3(), color) {
104
- super(color, rotation);
105
- this.pos = pos;
106
- vector3ToPixelRatio(this.pos);
107
- this.rotation = rotation;
294
+ export class EmptyElement extends SimulationElement3d {
295
+ geometry = new BlankGeometry();
296
+ label;
297
+ isEmpty = true;
298
+ constructor(label) {
299
+ super(vector3(), vector3());
300
+ this.label = label || null;
108
301
  }
109
- rotate(amount, t = 0, f) {
110
- const finalRotation = cloneBuf(this.rotation);
111
- vec3.add(finalRotation, amount, finalRotation);
112
- return transitionValues((p) => {
113
- this.rotation[0] += amount[0] * p;
114
- this.rotation[1] += amount[1] * p;
115
- this.rotation[2] += amount[2] * p;
116
- this.vertexCache.updated();
117
- }, () => {
118
- this.rotation = finalRotation;
119
- this.vertexCache.updated();
120
- }, t, f);
121
- }
122
- rotateTo(rot, t = 0, f) {
123
- const diff = vector3();
124
- vec3.sub(rot, this.rotation, diff);
125
- return transitionValues((p) => {
126
- this.rotation[0] += diff[0] * p;
127
- this.rotation[1] += diff[1] * p;
128
- this.rotation[2] += diff[2] * p;
129
- this.vertexCache.updated();
130
- }, () => {
131
- this.rotation = rot;
132
- this.vertexCache.updated();
133
- }, t, f);
134
- }
135
- move(amount, t = 0, f) {
136
- const finalPos = cloneBuf(this.pos);
137
- vec3.add(finalPos, amount, finalPos);
138
- return transitionValues((p) => {
139
- this.pos[0] += amount[0] * p;
140
- this.pos[1] += amount[1] * p;
141
- this.pos[2] += amount[2] * p;
142
- this.vertexCache.updated();
143
- }, () => {
144
- this.pos = finalPos;
145
- this.vertexCache.updated();
146
- }, t, f);
147
- }
148
- moveTo(pos, t = 0, f) {
149
- const diff = vector3();
150
- vec3.sub(pos, this.pos, diff);
151
- return transitionValues((p) => {
152
- this.pos[0] += diff[0] * p;
153
- this.pos[1] += diff[1] * p;
154
- this.pos[2] += diff[2] * p;
155
- this.vertexCache.updated();
156
- }, () => {
157
- this.pos = pos;
158
- this.vertexCache.updated();
159
- }, t, f);
302
+ getLabel() {
303
+ return this.label;
160
304
  }
305
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
306
+ onDeviceChange(_device) { }
161
307
  }
162
- export class SimulationElement2d extends SimulationElement {
163
- pos;
164
- rotation;
165
- constructor(pos, rotation = 0, color) {
166
- super(color, rotation);
167
- this.pos = pos;
168
- this.rotation = rotation;
308
+ export class SimulationElement2d extends SimulationElement3d {
309
+ is3d = false;
310
+ constructor(pos, rotation = vector3(), color) {
311
+ super(vector3FromVector2(pos), rotation, color);
312
+ vector3ToPixelRatio(this.pos);
169
313
  }
170
- rotate(rotation, t = 0, f) {
171
- const finalRotation = this.rotation + rotation;
172
- return transitionValues((p) => {
173
- this.rotation += rotation * p;
174
- this.vertexCache.updated();
175
- }, () => {
176
- this.rotation = finalRotation;
177
- this.vertexCache.updated();
178
- }, t, f);
314
+ rotate2d(amount, t = 0, f) {
315
+ return super.rotate(vector3(0, 0, amount), t, f);
179
316
  }
180
- rotateTo(newRotation, t = 0, f) {
181
- const diff = newRotation - this.rotation;
182
- return transitionValues((p) => {
183
- this.rotation += diff * p;
184
- this.vertexCache.updated();
185
- }, () => {
186
- this.rotation = newRotation;
187
- this.vertexCache.updated();
188
- }, t, f);
189
- }
190
- move(amount, t = 0, f) {
191
- const tempAmount = cloneBuf(amount);
192
- vector2ToPixelRatio(tempAmount);
193
- const finalPos = vector2();
194
- vec3.add(tempAmount, this.pos, finalPos);
195
- return transitionValues((p) => {
196
- this.pos[0] += tempAmount[0] * p;
197
- this.pos[1] += tempAmount[1] * p;
198
- this.vertexCache.updated();
199
- }, () => {
200
- this.pos = finalPos;
201
- this.vertexCache.updated();
202
- }, t, f);
317
+ rotateTo2d(rot, t = 0, f) {
318
+ return super.rotateTo(vector3(0, 0, rot), t, f);
203
319
  }
204
- moveTo(newPos, t = 0, f) {
205
- const pos = cloneBuf(newPos);
206
- vector2ToPixelRatio(pos);
207
- const diff = vector2();
208
- vec2.sub(pos, this.pos, diff);
209
- return transitionValues((p) => {
210
- this.pos[0] += diff[0] * p;
211
- this.pos[1] += diff[1] * p;
212
- this.vertexCache.updated();
213
- }, () => {
214
- this.pos = pos;
215
- this.vertexCache.updated();
216
- }, t, f);
320
+ getModelMatrix() {
321
+ super.updateModelMatrix2d();
322
+ return this.modelMatrix;
217
323
  }
218
324
  }
219
325
  export class Plane extends SimulationElement3d {
@@ -229,9 +335,8 @@ export class Plane extends SimulationElement3d {
229
335
  this.points = newPoints;
230
336
  this.vertexCache.updated();
231
337
  }
232
- updateMatrix(camera) {
233
- this.defaultUpdateMatrix(camera);
234
- }
338
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
339
+ onDeviceChange(_device) { }
235
340
  }
236
341
  export class Square extends SimulationElement2d {
237
342
  geometry;
@@ -243,14 +348,23 @@ export class Square extends SimulationElement2d {
243
348
  * @param vertexColors{Record<number, Color>} - 0 is top left vertex, numbers increase clockwise
244
349
  */
245
350
  constructor(pos, width, height, color, rotation, centerOffset, vertexColors) {
246
- super(pos, rotation, color);
247
- vector2ToPixelRatio(this.pos);
351
+ super(pos, vector3(0, 0, rotation), color);
248
352
  this.width = width * devicePixelRatio;
249
353
  this.height = height * devicePixelRatio;
250
354
  this.vertexColors = this.cloneColorMap(vertexColors || {});
251
355
  this.geometry = new SquareGeometry(this.width, this.height, centerOffset);
252
356
  this.geometry.setVertexColorMap(this.vertexColors);
253
357
  }
358
+ setOffset(offset) {
359
+ this.geometry.setOffset(offset);
360
+ }
361
+ setOffsetInplace(offset) {
362
+ const diff = vector3FromVector2(offset);
363
+ vec2.sub(diff, this.geometry.getOffset(), diff);
364
+ vec2.mul(diff, vector2(this.width / devicePixelRatio, -this.height / devicePixelRatio), diff);
365
+ this.setOffset(offset);
366
+ this.move(diff);
367
+ }
254
368
  cloneColorMap(colorMap) {
255
369
  const newColorMap = {};
256
370
  Object.entries(colorMap).forEach(([key, value]) => {
@@ -276,7 +390,7 @@ export class Square extends SimulationElement2d {
276
390
  diffMap[+key] = clone;
277
391
  }
278
392
  });
279
- return transitionValues((p) => {
393
+ return internalTransitionValues((p) => {
280
394
  Object.entries(diffMap).forEach(([key, value]) => {
281
395
  const color = this.vertexColors[+key];
282
396
  color.r += value.r * p;
@@ -296,7 +410,7 @@ export class Square extends SimulationElement2d {
296
410
  scaleWidth(amount, t = 0, f) {
297
411
  const finalWidth = this.width * amount;
298
412
  const diffWidth = finalWidth - this.width;
299
- return transitionValues((p) => {
413
+ return internalTransitionValues((p) => {
300
414
  this.width += diffWidth * p;
301
415
  this.geometry.setWidth(this.width);
302
416
  this.vertexCache.updated();
@@ -309,7 +423,7 @@ export class Square extends SimulationElement2d {
309
423
  scaleHeight(amount, t = 0, f) {
310
424
  const finalHeight = this.height * amount;
311
425
  const diffHeight = finalHeight - this.height;
312
- return transitionValues((p) => {
426
+ return internalTransitionValues((p) => {
313
427
  this.height += diffHeight * p;
314
428
  this.geometry.setHeight(this.height);
315
429
  this.vertexCache.updated();
@@ -324,7 +438,7 @@ export class Square extends SimulationElement2d {
324
438
  const finalHeight = this.height * amount;
325
439
  const diffWidth = finalWidth - this.width;
326
440
  const diffHeight = finalHeight - this.height;
327
- return transitionValues((p) => {
441
+ return internalTransitionValues((p) => {
328
442
  this.width += diffWidth * p;
329
443
  this.height += diffHeight * p;
330
444
  this.geometry.setWidth(this.width);
@@ -341,7 +455,7 @@ export class Square extends SimulationElement2d {
341
455
  setWidth(num, t = 0, f) {
342
456
  num *= devicePixelRatio;
343
457
  const diffWidth = num - this.width;
344
- return transitionValues((p) => {
458
+ return internalTransitionValues((p) => {
345
459
  this.width += diffWidth * p;
346
460
  this.geometry.setWidth(this.width);
347
461
  this.vertexCache.updated();
@@ -354,7 +468,7 @@ export class Square extends SimulationElement2d {
354
468
  setHeight(num, t = 0, f) {
355
469
  num *= devicePixelRatio;
356
470
  const diffHeight = num - this.height;
357
- return transitionValues((p) => {
471
+ return internalTransitionValues((p) => {
358
472
  this.height += diffHeight * p;
359
473
  this.geometry.setHeight(this.height);
360
474
  this.vertexCache.updated();
@@ -364,30 +478,23 @@ export class Square extends SimulationElement2d {
364
478
  this.vertexCache.updated();
365
479
  }, t, f);
366
480
  }
367
- updateMatrix(camera) {
368
- const pos = cloneBuf(this.pos);
369
- pos[1] = camera.getScreenSize()[1] + pos[1];
370
- const matrix = matrix4();
371
- mat4.translate(matrix, vector3FromVector2(pos), matrix);
372
- mat4.rotateZ(matrix, this.rotation, matrix);
373
- this.geometry.updateMatrix(matrix);
374
- }
481
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
482
+ onDeviceChange(_device) { }
375
483
  }
376
484
  export class Circle extends SimulationElement2d {
377
485
  geometry;
378
486
  radius;
379
487
  detail;
380
488
  constructor(pos, radius, color, detail = 50) {
381
- super(pos, 0, color);
382
- vector2ToPixelRatio(this.pos);
383
- this.radius = radius;
489
+ super(pos, vector3(), color);
490
+ this.radius = radius * devicePixelRatio;
384
491
  this.detail = detail;
385
492
  this.geometry = new CircleGeometry(this.radius, this.detail);
386
493
  }
387
494
  setRadius(num, t = 0, f) {
388
495
  num *= devicePixelRatio;
389
496
  const diff = num - this.radius;
390
- return transitionValues((p) => {
497
+ return internalTransitionValues((p) => {
391
498
  this.radius += diff * p;
392
499
  this.geometry.setRadius(this.radius);
393
500
  this.vertexCache.updated();
@@ -400,7 +507,7 @@ export class Circle extends SimulationElement2d {
400
507
  scale(amount, t = 0, f) {
401
508
  const finalRadius = this.radius * amount;
402
509
  const diff = finalRadius - this.radius;
403
- return transitionValues((p) => {
510
+ return internalTransitionValues((p) => {
404
511
  this.radius += diff * p;
405
512
  this.geometry.setRadius(this.radius);
406
513
  this.vertexCache.updated();
@@ -410,15 +517,14 @@ export class Circle extends SimulationElement2d {
410
517
  this.vertexCache.updated();
411
518
  }, t, f);
412
519
  }
413
- updateMatrix(camera) {
414
- this.defaultUpdateMatrix(camera);
415
- }
520
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
521
+ onDeviceChange(_device) { }
416
522
  }
417
523
  export class Polygon extends SimulationElement2d {
418
524
  geometry;
419
525
  vertices;
420
526
  constructor(pos, points, color, rotation) {
421
- super(pos, rotation, color);
527
+ super(pos, vector3(0, 0, rotation), color);
422
528
  this.vertices = points;
423
529
  this.geometry = new PolygonGeometry(this.vertices);
424
530
  }
@@ -429,14 +535,13 @@ export class Polygon extends SimulationElement2d {
429
535
  const vertices = newVertices.map((vert) => {
430
536
  const newVertex = vert.clone();
431
537
  newVertex.setZ(0);
432
- newVertex.setIs3d(false);
433
538
  return newVertex;
434
539
  });
435
- const lastVert = this.vertices.length > 0 ? this.vertices[this.vertices.length - 1] : vertex(0, 0, 0, color(), false);
540
+ const lastVert = this.vertices.length > 0 ? this.vertices[this.vertices.length - 1] : vertex(0, 0, 0, color());
436
541
  if (vertices.length > this.vertices.length) {
437
542
  while (vertices.length > this.vertices.length) {
438
543
  const lastPos = lastVert.getPos();
439
- this.vertices.push(new Vertex(lastPos[0], lastPos[1], 0, lastVert.getColor() || this.color, false));
544
+ this.vertices.push(new Vertex(lastPos[0], lastPos[1], 0, lastVert.getColor() || this.color));
440
545
  }
441
546
  }
442
547
  const initialPositions = this.vertices.map((p) => cloneBuf(p.getPos()));
@@ -467,7 +572,7 @@ export class Polygon extends SimulationElement2d {
467
572
  })
468
573
  : [])
469
574
  ];
470
- return transitionValues((p) => {
575
+ return internalTransitionValues((p) => {
471
576
  this.vertices.forEach((vert, i) => {
472
577
  const posChange = cloneBuf(posChanges[i]);
473
578
  const colorChange = cloneBuf(colorChanges[i]);
@@ -492,9 +597,8 @@ export class Polygon extends SimulationElement2d {
492
597
  this.vertexCache.updated();
493
598
  }, t, f);
494
599
  }
495
- updateMatrix(camera) {
496
- this.defaultUpdateMatrix(camera);
497
- }
600
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
601
+ onDeviceChange(_device) { }
498
602
  }
499
603
  export class Line3d extends SimulationElement3d {
500
604
  geometry;
@@ -506,7 +610,7 @@ export class Line3d extends SimulationElement3d {
506
610
  this.to = to.getPos();
507
611
  vec3.scale(this.to, devicePixelRatio, this.to);
508
612
  vec3.sub(this.to, this.pos, this.to);
509
- this.geometry = new Line3dGeometry(this.pos, this.to, this.thickness);
613
+ this.geometry = new Line3dGeometry(this.pos, this.to, this.thickness, pos.getColor() || this.getColor(), to.getColor());
510
614
  }
511
615
  setStart(pos, t = 0, f) {
512
616
  return this.moveTo(pos, t, f);
@@ -514,7 +618,7 @@ export class Line3d extends SimulationElement3d {
514
618
  setEnd(pos, t = 0, f) {
515
619
  const diff = vector3();
516
620
  vec3.sub(pos, this.to, diff);
517
- return transitionValues((p) => {
621
+ return internalTransitionValues((p) => {
518
622
  this.to[0] += diff[0] * p;
519
623
  this.to[1] += diff[1] * p;
520
624
  this.to[2] += diff[2] * p;
@@ -526,32 +630,30 @@ export class Line3d extends SimulationElement3d {
526
630
  this.vertexCache.updated();
527
631
  }, t, f);
528
632
  }
529
- updateMatrix(camera) {
530
- return this.defaultUpdateMatrix(camera);
531
- }
633
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
634
+ onDeviceChange(_device) { }
532
635
  }
533
636
  export class Line2d extends SimulationElement2d {
534
637
  geometry;
535
638
  to;
536
639
  thickness;
537
640
  constructor(from, to, thickness = 1) {
538
- super(vector2FromVector3(from.getPos()), 0, from.getColor() || undefined);
641
+ super(vector2FromVector3(from.getPos()), vector3(), from.getColor() || undefined);
539
642
  this.thickness = thickness * devicePixelRatio;
540
- this.to = vector2FromVector3(to.getPos());
541
- vec2.scale(this.to, devicePixelRatio, this.to);
643
+ this.to = to.getPos();
542
644
  vec2.sub(this.to, this.pos, this.to);
543
- this.geometry = new Line2dGeometry(this.pos, this.to, this.thickness);
645
+ this.geometry = new Line2dGeometry(this.pos, this.to, this.thickness, from.getColor() || this.getColor(), to.getColor());
544
646
  }
545
647
  setStart(pos, t = 0, f) {
546
648
  return this.moveTo(pos, t, f);
547
649
  }
548
650
  setEnd(pos, t = 0, f) {
549
651
  const tempPos = cloneBuf(pos);
550
- vector2ToPixelRatio(tempPos);
551
- vec2.sub(tempPos, this.getPos(), tempPos);
652
+ vector3ToPixelRatio(tempPos);
653
+ // vec2.sub(tempPos, this.getPos(), tempPos);
552
654
  const diff = vector3();
553
655
  vec2.sub(tempPos, this.to, diff);
554
- return transitionValues((p) => {
656
+ return internalTransitionValues((p) => {
555
657
  this.to[0] += diff[0] * p;
556
658
  this.to[1] += diff[1] * p;
557
659
  this.vertexCache.updated();
@@ -561,27 +663,26 @@ export class Line2d extends SimulationElement2d {
561
663
  this.vertexCache.updated();
562
664
  }, t, f);
563
665
  }
564
- updateMatrix(camera) {
565
- return this.defaultUpdateMatrix(camera);
566
- }
666
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
667
+ onDeviceChange(_device) { }
567
668
  }
568
669
  export class Cube extends SimulationElement3d {
569
670
  geometry;
570
671
  width;
571
672
  height;
572
673
  depth;
573
- constructor(pos, width, height, depth, color, rotation) {
674
+ constructor(pos, width, height, depth, color, rotation = vector3()) {
574
675
  super(pos, rotation, color);
575
- this.width = width * devicePixelRatio;
576
- this.height = height * devicePixelRatio;
577
- this.depth = depth * devicePixelRatio;
676
+ this.width = width;
677
+ this.height = height;
678
+ this.depth = depth;
578
679
  this.rotation = rotation || vector3();
579
680
  this.geometry = new CubeGeometry(this.width, this.height, this.depth);
580
681
  }
581
682
  setWidth(width, t = 0, f) {
582
683
  width *= devicePixelRatio;
583
684
  const diff = width - this.width;
584
- return transitionValues((p) => {
685
+ return internalTransitionValues((p) => {
585
686
  this.width += diff * p;
586
687
  this.geometry.setWidth(this.width);
587
688
  this.vertexCache.updated();
@@ -594,7 +695,7 @@ export class Cube extends SimulationElement3d {
594
695
  setHeight(height, t = 0, f) {
595
696
  height *= devicePixelRatio;
596
697
  const diff = height - this.width;
597
- return transitionValues((p) => {
698
+ return internalTransitionValues((p) => {
598
699
  this.height += diff * p;
599
700
  this.geometry.setHeight(this.height);
600
701
  this.vertexCache.updated();
@@ -607,7 +708,7 @@ export class Cube extends SimulationElement3d {
607
708
  setDepth(depth, t = 0, f) {
608
709
  depth *= devicePixelRatio;
609
710
  const diff = depth - this.width;
610
- return transitionValues((p) => {
711
+ return internalTransitionValues((p) => {
611
712
  this.depth += diff * p;
612
713
  this.geometry.setDepth(this.depth);
613
714
  this.vertexCache.updated();
@@ -624,7 +725,7 @@ export class Cube extends SimulationElement3d {
624
725
  const widthDiff = finalWidth - this.width;
625
726
  const heightDiff = finalHeight - this.height;
626
727
  const depthDiff = finalDepth - this.depth;
627
- return transitionValues((p) => {
728
+ return internalTransitionValues((p) => {
628
729
  this.width += widthDiff * p;
629
730
  this.height += heightDiff * p;
630
731
  this.depth += depthDiff * p;
@@ -642,9 +743,8 @@ export class Cube extends SimulationElement3d {
642
743
  this.vertexCache.updated();
643
744
  }, t, f);
644
745
  }
645
- updateMatrix(camera) {
646
- this.defaultUpdateMatrix(camera);
647
- }
746
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
747
+ onDeviceChange(_device) { }
648
748
  }
649
749
  export class BezierCurve2d {
650
750
  points;
@@ -796,8 +896,7 @@ export class Spline2d extends SimulationElement2d {
796
896
  length;
797
897
  constructor(pos, points, thickness = devicePixelRatio, detail = 40) {
798
898
  const tempPos = vector2FromVector3(pos.getPos());
799
- vector2ToPixelRatio(tempPos);
800
- super(tempPos, 0, pos.getColor() || undefined);
899
+ super(tempPos, vector3(), pos.getColor() || undefined);
801
900
  this.thickness = thickness * devicePixelRatio;
802
901
  this.detail = detail;
803
902
  this.interpolateStart = 0;
@@ -818,7 +917,7 @@ export class Spline2d extends SimulationElement2d {
818
917
  }
819
918
  setInterpolateStart(start, t = 0, f) {
820
919
  const diff = start - this.interpolateStart;
821
- return transitionValues((p) => {
920
+ return internalTransitionValues((p) => {
822
921
  this.interpolateStart += diff * p;
823
922
  this.geometry.updateInterpolationStart(this.interpolateStart);
824
923
  this.vertexCache.updated();
@@ -830,7 +929,7 @@ export class Spline2d extends SimulationElement2d {
830
929
  }
831
930
  setInterpolateLimit(limit, t = 0, f) {
832
931
  const diff = limit - this.interpolateLimit;
833
- return transitionValues((p) => {
932
+ return internalTransitionValues((p) => {
834
933
  this.interpolateLimit += diff * p;
835
934
  this.geometry.updateInterpolationLimit(this.interpolateLimit);
836
935
  this.vertexCache.updated();
@@ -849,7 +948,7 @@ export class Spline2d extends SimulationElement2d {
849
948
  const clonePoint = newPoint.clone();
850
949
  const start = clonePoint.getStart()?.getPos() || vector3();
851
950
  const end = clonePoint.getEnd().getPos();
852
- const pos = vector3FromVector2(this.getPos());
951
+ const pos = this.getPos();
853
952
  vec3.sub(start, pos, start);
854
953
  vec3.sub(end, pos, end);
855
954
  this.geometry.updatePoint(pointIndex, clonePoint);
@@ -859,7 +958,7 @@ export class Spline2d extends SimulationElement2d {
859
958
  setThickness(thickness, t = 0, f) {
860
959
  thickness *= devicePixelRatio;
861
960
  const diff = thickness - this.thickness;
862
- return transitionValues((p) => {
961
+ return internalTransitionValues((p) => {
863
962
  this.thickness += diff * p;
864
963
  this.geometry.updateThickness(this.thickness);
865
964
  this.vertexCache.updated();
@@ -893,34 +992,26 @@ export class Spline2d extends SimulationElement2d {
893
992
  const [vec] = this.interpolateSlope(t);
894
993
  return vec;
895
994
  }
896
- updateMatrix(camera) {
897
- this.defaultUpdateMatrix(camera);
898
- }
995
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
996
+ onDeviceChange(_device) { }
899
997
  }
900
998
  export class Instance extends SimulationElement3d {
901
999
  geometry;
902
1000
  obj;
903
1001
  instanceMatrix;
904
1002
  matrixBuffer;
905
- device;
906
1003
  baseMat;
907
- needsRemap = false;
1004
+ isInstance = true;
908
1005
  constructor(obj, numInstances) {
909
- super(vector3());
910
- this.device = null;
1006
+ super(vector3(), vector3());
911
1007
  this.matrixBuffer = null;
912
1008
  obj.isInstanced = true;
913
1009
  this.obj = obj;
914
1010
  this.instanceMatrix = [];
915
- this.is3d = Boolean(obj.is3d);
1011
+ this.is3d = obj.is3d;
916
1012
  this.geometry = new BlankGeometry();
917
1013
  this.baseMat = matrix4();
918
- if (typeof obj.getRotation() === 'number') {
919
- mat4.rotateZ(this.baseMat, obj.getRotation(), this.baseMat);
920
- }
921
- else {
922
- rotateMat4(this.baseMat, obj.getRotation());
923
- }
1014
+ rotateMat4(this.baseMat, obj.getRotation());
924
1015
  for (let i = 0; i < numInstances; i++) {
925
1016
  const clone = cloneBuf(this.baseMat);
926
1017
  this.instanceMatrix.push(clone);
@@ -945,35 +1036,18 @@ export class Instance extends SimulationElement3d {
945
1036
  const clone = cloneBuf(this.baseMat);
946
1037
  this.instanceMatrix[i] = clone;
947
1038
  }
948
- if (this.device) {
949
- this.setMatrixBuffer();
950
- this.needsRemap = true;
951
- }
952
1039
  }
953
1040
  setInstance(instance, transformation) {
954
1041
  if (instance >= this.instanceMatrix.length || instance < 0)
955
1042
  return;
956
1043
  this.instanceMatrix[instance] = transformation;
957
- this.needsRemap = true;
958
1044
  }
959
- mapBuffer() {
960
- if (!this.device || this.matrixBuffer === null)
1045
+ mapBuffer(device) {
1046
+ if (this.matrixBuffer === null)
961
1047
  return;
962
1048
  const buf = new Float32Array(this.instanceMatrix.map((mat) => [...mat]).flat());
963
- this.device.queue.writeBuffer(this.matrixBuffer, 0, buf.buffer, buf.byteOffset, buf.byteLength);
1049
+ device.queue.writeBuffer(this.matrixBuffer, 0, buf.buffer, buf.byteOffset, buf.byteLength);
964
1050
  this.matrixBuffer.unmap();
965
- this.needsRemap = false;
966
- }
967
- setMatrixBuffer() {
968
- if (!this.device || this.instanceMatrix.length === 0)
969
- return;
970
- const minSize = 640;
971
- const size = Math.max(minSize, this.instanceMatrix[0].byteLength * this.instanceMatrix.length);
972
- this.matrixBuffer = this.device.createBuffer({
973
- size,
974
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
975
- });
976
- this.needsRemap = true;
977
1051
  }
978
1052
  getInstances() {
979
1053
  return this.instanceMatrix;
@@ -981,13 +1055,16 @@ export class Instance extends SimulationElement3d {
981
1055
  getNumInstances() {
982
1056
  return this.instanceMatrix.length;
983
1057
  }
984
- setDevice(device) {
985
- this.device = device;
986
- if (this.matrixBuffer === null) {
987
- this.setMatrixBuffer();
1058
+ getMatrixBuffer(device) {
1059
+ if (!this.matrixBuffer) {
1060
+ const minSize = 512;
1061
+ const size = Math.max(minSize, this.instanceMatrix[0].byteLength * this.instanceMatrix.length);
1062
+ this.matrixBuffer = device.createBuffer({
1063
+ size,
1064
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
1065
+ });
988
1066
  }
989
- }
990
- getMatrixBuffer() {
1067
+ this.mapBuffer(device);
991
1068
  return this.matrixBuffer;
992
1069
  }
993
1070
  getVertexCount() {
@@ -996,11 +1073,53 @@ export class Instance extends SimulationElement3d {
996
1073
  getGeometryType() {
997
1074
  return this.obj.getGeometryType();
998
1075
  }
1076
+ getBuffer() {
1077
+ return this.obj.getBuffer();
1078
+ }
1079
+ onDeviceChange(device) {
1080
+ this.obj.propagateDevice(device);
1081
+ }
1082
+ getModelMatrix() {
1083
+ return this.obj.getModelMatrix();
1084
+ }
1085
+ }
1086
+ export class TraceLines2d extends SimulationElement2d {
1087
+ geometry;
1088
+ constructor(color, maxLen) {
1089
+ super(vector2(), vector3(), color);
1090
+ this.geometry = new TraceLinesGeometry(maxLen);
1091
+ }
1092
+ addPoint(point, color) {
1093
+ const vert = vertex(point[0], point[1], point?.[2] || 0, color);
1094
+ this.geometry.addVertex(vert);
1095
+ this.vertexCache.updated();
1096
+ }
1097
+ // always being wireframe means that triangleOrder
1098
+ // in in the geometry does not need to be a duplicate
1099
+ // of wireframeOrder
1100
+ isWireframe() {
1101
+ return true;
1102
+ }
999
1103
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
1000
- updateMatrix(_) { }
1001
- getBuffer(camera) {
1002
- if (this.needsRemap)
1003
- this.mapBuffer();
1004
- return this.obj.getBuffer(camera);
1104
+ onDeviceChange(_) { }
1105
+ }
1106
+ export class TraceLines3d extends SimulationElement3d {
1107
+ geometry;
1108
+ constructor(color, maxLen) {
1109
+ super(vector3(), vector3(), color);
1110
+ this.geometry = new TraceLinesGeometry(maxLen);
1005
1111
  }
1112
+ addPoint(point, color) {
1113
+ const vert = vertex(point[0], point[1], point?.[2] || 0, color);
1114
+ this.geometry.addVertex(vert);
1115
+ this.vertexCache.updated();
1116
+ }
1117
+ // always being wireframe means that triangleOrder
1118
+ // in in the geometry does not need to be a duplicate
1119
+ // of wireframeOrder
1120
+ isWireframe() {
1121
+ return true;
1122
+ }
1123
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1124
+ onDeviceChange(_) { }
1006
1125
  }