simulationjsv2 0.7.3 → 0.8.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/dist/graphics.js CHANGED
@@ -1,16 +1,23 @@
1
- import { vec3, mat4, vec2, vec4 } from 'wgpu-matrix';
2
- import { Vertex, cloneBuf, color, colorFromVector4, vector2, vector3, vertex, Color, vector2FromVector3, matrix4, vector3FromVector2, distance2d } from './utils.js';
1
+ import { vec3, mat4, vec2 } from 'wgpu-matrix';
2
+ import { cloneBuf, vector2, vector3, Color, vector2FromVector3, matrix4, vector3FromVector2, distance2d, color, interpolateColors } from './utils.js';
3
3
  import { BlankGeometry, CircleGeometry, CubeGeometry, Line2dGeometry, Line3dGeometry, PlaneGeometry, PolygonGeometry, Spline2dGeometry, SquareGeometry, TraceLines2dGeometry as TraceLinesGeometry } from './geometry.js';
4
- import { SimSceneObjInfo, VertexCache, bufferGenerator, globalInfo, internalTransitionValues, logger, posTo2dScreen, vector3ToPixelRatio } from './internalUtils.js';
4
+ import { SimSceneObjInfo, Float32ArrayCache, internalTransitionValues, posTo2dScreen, vector3ToPixelRatio } from './internalUtils.js';
5
5
  import { mat4ByteLength, modelProjMatOffset } from './constants.js';
6
+ import { MemoBuffer } from './buffers.js';
7
+ import { globalInfo, logger, pipelineCache } from './globals.js';
8
+ import { defaultShader, uniformBufferSize, vertexColorShader } from './shaders.js';
9
+ import { BasicMaterial, VertexColorMaterial } from './materials.js';
6
10
  export class SimulationElement3d {
7
11
  children;
8
12
  uniformBuffer;
13
+ prevInfo;
14
+ pipeline;
15
+ shader;
16
+ material;
17
+ cullMode;
9
18
  parent;
10
19
  centerOffset;
11
- rotationOffset;
12
20
  pos;
13
- color;
14
21
  wireframe;
15
22
  vertexCache;
16
23
  rotation;
@@ -25,16 +32,18 @@ export class SimulationElement3d {
25
32
  constructor(pos, rotation, color = new Color()) {
26
33
  this.pos = pos;
27
34
  this.centerOffset = vector3();
28
- // TODO test this
29
- this.rotationOffset = vector3();
30
- this.color = color;
31
- this.vertexCache = new VertexCache();
35
+ this.vertexCache = new Float32ArrayCache();
32
36
  this.wireframe = false;
33
37
  this.rotation = cloneBuf(rotation);
34
- this.uniformBuffer = null;
38
+ this.uniformBuffer = new MemoBuffer(GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, uniformBufferSize);
35
39
  this.children = [];
36
40
  this.modelMatrix = matrix4();
37
41
  this.parent = null;
42
+ this.pipeline = null;
43
+ this.prevInfo = null;
44
+ this.shader = defaultShader;
45
+ this.material = new BasicMaterial(color);
46
+ this.cullMode = 'back';
38
47
  }
39
48
  add(el, id) {
40
49
  el.setParent(this);
@@ -63,11 +72,20 @@ export class SimulationElement3d {
63
72
  getParent() {
64
73
  return this.parent;
65
74
  }
75
+ getCullMode() {
76
+ return this.cullMode;
77
+ }
78
+ setCullMode(mode) {
79
+ this.cullMode = mode;
80
+ }
66
81
  setCenterOffset(offset) {
67
82
  this.centerOffset = offset;
68
83
  }
69
- setRotationOffset(offset) {
70
- this.rotationOffset = offset;
84
+ getShader() {
85
+ return this.shader;
86
+ }
87
+ setShader(shader) {
88
+ this.shader = shader;
71
89
  }
72
90
  resetCenterOffset() {
73
91
  this.centerOffset[0] = 0;
@@ -78,23 +96,37 @@ export class SimulationElement3d {
78
96
  this.updateModelMatrix3d();
79
97
  return this.modelMatrix;
80
98
  }
81
- getUniformBuffer(mat) {
99
+ isTransparent() {
100
+ return this.material.isTransparent();
101
+ }
102
+ setMaterial(material) {
103
+ this.material = material;
104
+ }
105
+ getObjectInfo() {
106
+ const topologyString = this.isWireframe() ? 'line-strip' : 'triangle-' + this.getGeometryTopology();
107
+ return `{ "topology": "${topologyString}", "transparent": ${this.isTransparent()}, "cullMode": "${this.cullMode}" }`;
108
+ }
109
+ getUniformBuffer() {
110
+ const mat = this.getModelMatrix();
111
+ const device = globalInfo.errorGetDevice();
112
+ const buffer = this.uniformBuffer.getBuffer();
113
+ device.queue.writeBuffer(buffer, modelProjMatOffset, mat);
114
+ return buffer;
115
+ }
116
+ getPipeline() {
82
117
  const device = globalInfo.errorGetDevice();
83
- if (!this.uniformBuffer) {
84
- const uniformBufferSize = 4 * 16 + 4 * 16 + 4 * 2 + 8; // 4x4 matrix + 4x4 matrix + vec2<f32> + 8 bc 144 is cool
85
- this.uniformBuffer = device.createBuffer({
86
- size: uniformBufferSize,
87
- usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
88
- });
118
+ const objInfo = this.getObjectInfo();
119
+ if (!this.pipeline || !this.prevInfo || this.prevInfo !== objInfo) {
120
+ this.pipeline = pipelineCache.getPipeline(device, objInfo, this.shader);
121
+ this.prevInfo = objInfo;
89
122
  }
90
- device.queue.writeBuffer(this.uniformBuffer, modelProjMatOffset, mat);
91
- return this.uniformBuffer;
123
+ return this.pipeline;
92
124
  }
93
125
  mirrorParentTransforms3d(mat) {
94
126
  if (!this.parent)
95
127
  return;
96
128
  this.parent.mirrorParentTransforms3d(mat);
97
- mat4.translate(mat, this.parent.getPos(), mat);
129
+ mat4.translate(mat, this.parent.getRelativePos(), mat);
98
130
  const parentRot = this.parent.getRotation();
99
131
  mat4.rotateZ(mat, parentRot[2], mat);
100
132
  mat4.rotateY(mat, parentRot[1], mat);
@@ -106,12 +138,9 @@ export class SimulationElement3d {
106
138
  this.mirrorParentTransforms3d(this.modelMatrix);
107
139
  }
108
140
  mat4.translate(this.modelMatrix, this.pos, this.modelMatrix);
109
- // vec3.negate(this.rotationOffset, cachedVec1);
110
- // mat4.translate(this.modelMatrix, cachedVec1, this.modelMatrix);
111
141
  mat4.rotateZ(this.modelMatrix, this.rotation[2], this.modelMatrix);
112
142
  mat4.rotateY(this.modelMatrix, this.rotation[1], this.modelMatrix);
113
143
  mat4.rotateX(this.modelMatrix, this.rotation[0], this.modelMatrix);
114
- // mat4.translate(this.modelMatrix, this.rotationOffset, this.modelMatrix);
115
144
  mat4.translate(this.modelMatrix, this.centerOffset, this.modelMatrix);
116
145
  }
117
146
  mirrorParentTransforms2d(mat) {
@@ -135,11 +164,13 @@ export class SimulationElement3d {
135
164
  else {
136
165
  mat4.translate(this.modelMatrix, pos, this.modelMatrix);
137
166
  }
167
+ const negated = vec3.negate(this.centerOffset);
168
+ mat4.translate(this.modelMatrix, negated, this.modelMatrix);
138
169
  mat4.rotateZ(this.modelMatrix, this.rotation[2], this.modelMatrix);
139
170
  mat4.translate(this.modelMatrix, this.centerOffset, this.modelMatrix);
140
171
  }
141
- getGeometryType() {
142
- return this.geometry.getType();
172
+ getGeometryTopology() {
173
+ return this.geometry.getTopology();
143
174
  }
144
175
  setWireframe(wireframe) {
145
176
  this.wireframe = wireframe;
@@ -147,13 +178,13 @@ export class SimulationElement3d {
147
178
  isWireframe() {
148
179
  return this.wireframe;
149
180
  }
150
- getColor() {
151
- return this.color;
181
+ getMaterial() {
182
+ return this.material;
152
183
  }
153
- getPos() {
184
+ getRelativePos() {
154
185
  return this.pos;
155
186
  }
156
- getAbsolutePos() {
187
+ getPos() {
157
188
  const vec = vector3();
158
189
  this.updateModelMatrix3d();
159
190
  mat4.getTranslation(this.modelMatrix, vec);
@@ -166,16 +197,17 @@ export class SimulationElement3d {
166
197
  return this.centerOffset;
167
198
  }
168
199
  fill(newColor, t = 0, f) {
169
- const diff = newColor.diff(this.color);
200
+ const materialColor = this.material.getColor();
201
+ const diff = newColor.diff(materialColor);
170
202
  const finalColor = newColor.clone();
171
203
  return internalTransitionValues((p) => {
172
- this.color.r += diff.r * p;
173
- this.color.g += diff.g * p;
174
- this.color.b += diff.b * p;
175
- this.color.a += diff.a * p;
204
+ materialColor.r += diff.r * p;
205
+ materialColor.g += diff.g * p;
206
+ materialColor.b += diff.b * p;
207
+ materialColor.a += diff.a * p;
176
208
  this.vertexCache.updated();
177
209
  }, () => {
178
- this.color = finalColor;
210
+ this.material.setColor(finalColor);
179
211
  this.vertexCache.updated();
180
212
  }, t, f);
181
213
  }
@@ -253,38 +285,41 @@ export class SimulationElement3d {
253
285
  if (this.vertexCache.shouldUpdate()) {
254
286
  this.geometry.recompute();
255
287
  }
256
- let childrenVertices = 0;
288
+ let vertexCount = this.geometry.getIndexes(this.isWireframe()).length;
257
289
  for (let i = 0; i < this.children.length; i++) {
258
- childrenVertices += this.children[i].getObj().getVertexCount();
290
+ vertexCount += this.children[i].getObj().getVertexCount();
259
291
  }
260
- let currentVertices = 0;
261
- if (this.isWireframe()) {
262
- currentVertices = this.geometry.getWireframeVertexCount();
263
- }
264
- else {
265
- currentVertices = this.geometry.getTriangleVertexCount();
292
+ return vertexCount;
293
+ }
294
+ getIndexCount() {
295
+ let indexCount = this.geometry.getIndexes(this.isWireframe()).length;
296
+ for (let i = 0; i < this.children.length; i++) {
297
+ indexCount += this.children[i].getObj().getIndexCount();
266
298
  }
267
- return currentVertices + childrenVertices;
299
+ return indexCount;
300
+ }
301
+ writeBuffers() {
302
+ this.shader.writeBuffers(this);
268
303
  }
269
- getBuffer(vertexParamGenerator) {
304
+ getVertexBuffer() {
270
305
  if (this.vertexCache.shouldUpdate()) {
271
306
  this.geometry.recompute();
272
- if (this.isInstanced) {
273
- bufferGenerator.setInstancing(true);
307
+ const vertices = this.geometry.getVertices();
308
+ const stride = this.shader.getBufferLength();
309
+ const vertexBuffer = new Float32Array(vertices.length * stride);
310
+ const shader = this.isWireframe() ? defaultShader : this.shader;
311
+ for (let i = 0; i < vertices.length; i++) {
312
+ shader.setVertexInfo(this, vertexBuffer, vertices[i], i, i * stride);
274
313
  }
275
- let resBuffer;
276
- if (this.isWireframe()) {
277
- resBuffer = this.geometry.getWireframeBuffer(this.color, vertexParamGenerator);
278
- }
279
- else {
280
- resBuffer = this.geometry.getTriangleBuffer(this.color, vertexParamGenerator);
281
- }
282
- bufferGenerator.setInstancing(false);
283
- this.vertexCache.setCache(resBuffer);
284
- return resBuffer;
314
+ this.vertexCache.setCache(vertexBuffer);
315
+ return vertexBuffer;
285
316
  }
286
317
  return this.vertexCache.getCache();
287
318
  }
319
+ getIndexBuffer() {
320
+ const order = this.geometry.getIndexes(this.isWireframe());
321
+ return new Uint32Array(order);
322
+ }
288
323
  }
289
324
  export class EmptyElement extends SimulationElement3d {
290
325
  geometry = new BlankGeometry();
@@ -292,7 +327,7 @@ export class EmptyElement extends SimulationElement3d {
292
327
  isEmpty = true;
293
328
  constructor(label) {
294
329
  super(vector3(), vector3());
295
- this.label = label || null;
330
+ this.label = label ?? null;
296
331
  }
297
332
  getLabel() {
298
333
  return this.label;
@@ -323,6 +358,7 @@ export class Plane extends SimulationElement3d {
323
358
  this.rotation = rotation;
324
359
  this.points = points;
325
360
  this.geometry = new PlaneGeometry(points);
361
+ this.cullMode = 'none';
326
362
  }
327
363
  setPoints(newPoints) {
328
364
  this.points = newPoints;
@@ -333,70 +369,21 @@ export class Square extends SimulationElement2d {
333
369
  geometry;
334
370
  width;
335
371
  height;
336
- vertexColors;
337
372
  /**
338
373
  * @param centerOffset{Vector2} - A vector2 of values from 0 to 1
339
374
  * @param vertexColors{Record<number, Color>} - 0 is top left vertex, numbers increase clockwise
340
375
  */
341
- constructor(pos, width, height, color, rotation, centerOffset, vertexColors) {
376
+ constructor(pos, width, height, color, rotation) {
342
377
  super(pos, vector3(0, 0, rotation), color);
343
- this.width = width * devicePixelRatio;
344
- this.height = height * devicePixelRatio;
345
- this.vertexColors = this.cloneColorMap(vertexColors || {});
346
- this.geometry = new SquareGeometry(this.width, this.height, centerOffset);
347
- this.geometry.setVertexColorMap(this.vertexColors);
348
- }
349
- setOffset(offset) {
350
- this.geometry.setOffset(offset);
351
- }
352
- setOffsetInplace(offset) {
353
- const diff = vector3FromVector2(offset);
354
- vec2.sub(diff, this.geometry.getOffset(), diff);
355
- vec2.mul(diff, vector2(this.width / devicePixelRatio, -this.height / devicePixelRatio), diff);
356
- this.setOffset(offset);
357
- this.move(diff);
358
- }
359
- cloneColorMap(colorMap) {
360
- const newColorMap = {};
361
- Object.entries(colorMap).forEach(([key, value]) => {
362
- newColorMap[+key] = value.clone();
363
- });
364
- return newColorMap;
365
- }
366
- setVertexColors(newColorMap, t = 0, f) {
367
- const colorMap = this.cloneColorMap(newColorMap);
368
- const diffMap = {};
369
- Object.entries(colorMap).forEach(([key, value]) => {
370
- if (!this.vertexColors[+key]) {
371
- this.vertexColors[+key] = color();
372
- }
373
- diffMap[+key] = value.diff(this.vertexColors[+key] || color());
374
- });
375
- Object.entries(this.vertexColors).forEach(([key, value]) => {
376
- if (!diffMap[+key]) {
377
- const clone = value.clone();
378
- clone.r *= -1;
379
- clone.g *= -1;
380
- clone.b *= -1;
381
- diffMap[+key] = clone;
382
- }
383
- });
384
- return internalTransitionValues((p) => {
385
- Object.entries(diffMap).forEach(([key, value]) => {
386
- const color = this.vertexColors[+key];
387
- color.r += value.r * p;
388
- color.g += value.g * p;
389
- color.b += value.b * p;
390
- color.a += value.a * p;
391
- this.vertexColors[+key] = color;
392
- });
393
- this.geometry.setVertexColorMap(this.vertexColors);
394
- this.vertexCache.updated();
395
- }, () => {
396
- this.vertexColors = colorMap;
397
- this.geometry.setVertexColorMap(this.vertexColors);
398
- this.vertexCache.updated();
399
- }, t, f);
378
+ this.width = width;
379
+ this.height = height;
380
+ this.geometry = new SquareGeometry(this.width, this.height);
381
+ }
382
+ getWidth() {
383
+ return this.width;
384
+ }
385
+ getHeight() {
386
+ return this.height;
400
387
  }
401
388
  scaleWidth(amount, t = 0, f) {
402
389
  const finalWidth = this.width * amount;
@@ -509,78 +496,78 @@ export class Circle extends SimulationElement2d {
509
496
  }
510
497
  export class Polygon extends SimulationElement2d {
511
498
  geometry;
512
- vertices;
513
- constructor(pos, points, color, rotation) {
499
+ constructor(pos, vertices, color, rotation) {
514
500
  super(pos, vector3(0, 0, rotation), color);
515
- this.vertices = points;
516
- this.geometry = new PolygonGeometry(this.vertices);
501
+ const vectors = vertices.map((vert) => vert.getPos());
502
+ this.shader = vertexColorShader;
503
+ this.geometry = new PolygonGeometry(vectors);
504
+ this.material = new VertexColorMaterial();
505
+ if (color)
506
+ this.material.setColor(color);
507
+ const colors = vertices.map((vert) => vert.getColor() ?? this.material.getColor());
508
+ this.material.setVertexColors(colors);
517
509
  }
518
510
  getVertices() {
519
- return this.vertices;
520
- }
521
- setVertices(newVertices, t = 0, f) {
522
- const vertices = newVertices.map((vert) => {
523
- const newVertex = vert.clone();
524
- newVertex.setZ(0);
525
- return newVertex;
511
+ return this.geometry.getVertices();
512
+ }
513
+ setVertices(vertices, t = 0, f) {
514
+ const newVertices = vertices.map((vert) => vert.getPos());
515
+ const newColors = vertices.map((vert) => vert.getColor() ?? this.material.getColor());
516
+ const oldColors = this.material.getVertexColors();
517
+ const oldVertices = this.getVertices();
518
+ const lastVert = oldVertices.length > 0 ? oldVertices[oldVertices.length - 1] : vector3();
519
+ const lastColor = oldColors.length > 0 ? oldColors[oldColors.length - 1] : this.material.getColor();
520
+ while (newVertices.length > oldVertices.length) {
521
+ oldVertices.push(cloneBuf(lastVert));
522
+ oldColors.push(lastColor.clone());
523
+ }
524
+ // at this point oldVertices length is assumed to be greater than or equal to newVertices length
525
+ const initialPositions = oldVertices.map((vert) => cloneBuf(vert));
526
+ const posChanges = newVertices.map((vert, i) => {
527
+ const vec = vector3();
528
+ vec3.sub(vert, oldVertices[i], vec);
529
+ return vec;
526
530
  });
527
- const lastVert = this.vertices.length > 0 ? this.vertices[this.vertices.length - 1] : vertex(0, 0, 0, color());
528
- if (vertices.length > this.vertices.length) {
529
- while (vertices.length > this.vertices.length) {
530
- const lastPos = lastVert.getPos();
531
- this.vertices.push(new Vertex(lastPos[0], lastPos[1], 0, lastVert.getColor() || this.color));
532
- }
531
+ for (let i = newVertices.length; i < oldVertices.length; i++) {
532
+ const vec = cloneBuf(newVertices[newVertices.length - 1]);
533
+ vec3.sub(vec, oldVertices[i], vec);
534
+ posChanges.push(vec);
535
+ }
536
+ const initialColors = oldColors.map((oldColor) => oldColor.clone());
537
+ const colorChanges = newColors.map((currentColor, index) => currentColor.diff(oldColors[index]));
538
+ for (let i = newVertices.length; i < oldVertices.length; i++) {
539
+ colorChanges.push(newColors[newColors.length - 1].diff(oldColors[i]));
533
540
  }
534
- const initialPositions = this.vertices.map((p) => cloneBuf(p.getPos()));
535
- const posChanges = [
536
- ...vertices.map((vert, i) => {
537
- const vec = vector3();
538
- vec3.sub(vert.getPos(), this.vertices[i].getPos(), vec);
539
- return cloneBuf(vec);
540
- }),
541
- ...(this.vertices.length > vertices.length
542
- ? this.vertices.slice(vertices.length, this.vertices.length).map((vert) => {
543
- const vec = cloneBuf(vertices[vertices.length - 1].getPos());
544
- vec3.sub(vec, vert.getPos(), vec);
545
- return vec;
546
- })
547
- : [])
548
- ];
549
- const initialColors = this.vertices.map((vert) => (vert.getColor() || this.color).toVec4());
550
- const colorChanges = [
551
- ...vertices.map((vert, i) => {
552
- const diff = (vert.getColor() || this.color).diff(this.vertices[i].getColor() || this.color);
553
- return diff.toVec4();
554
- }),
555
- ...(this.vertices.length > vertices.length
556
- ? this.vertices.slice(vertices.length, this.vertices.length).map((vert) => {
557
- const toColor = vertices[vertices.length - 1].getColor();
558
- return (toColor || this.color).diff(vert.getColor() || this.color).toVec4();
559
- })
560
- : [])
561
- ];
562
541
  return internalTransitionValues((p) => {
563
- this.vertices.forEach((vert, i) => {
542
+ for (let i = 0; i < oldVertices.length; i++) {
543
+ const vert = oldVertices[i];
544
+ const currentColor = oldColors[i];
564
545
  const posChange = cloneBuf(posChanges[i]);
565
- const colorChange = cloneBuf(colorChanges[i]);
546
+ const colorChange = colorChanges[i].clone();
566
547
  vec3.scale(posChange, p, posChange);
567
- vec3.add(vert.getPos(), posChange, posChange);
568
- vec4.scale(colorChange, p, colorChange);
569
- vec4.add((vert.getColor() || this.color).toVec4(), colorChange, colorChange);
570
- vert.setPos(posChange);
571
- vert.setColor(colorFromVector4(colorChange));
572
- });
548
+ vec3.add(vert, posChange, vert);
549
+ currentColor.r += colorChange.r * p;
550
+ currentColor.g += colorChange.g * p;
551
+ currentColor.b += colorChange.b * p;
552
+ currentColor.a += colorChange.a * p;
553
+ }
573
554
  this.vertexCache.updated();
574
555
  }, () => {
575
- this.vertices.forEach((vert, i) => {
556
+ for (let i = 0; i < oldVertices.length; i++) {
557
+ const vert = oldVertices[i];
558
+ const currentColor = oldColors[i];
576
559
  const initPos = initialPositions[i];
577
560
  const initColor = initialColors[i];
578
561
  vec3.add(initPos, posChanges[i], initPos);
579
- vec4.add(initColor, colorChanges[i], initColor);
580
- vert.setPos(initPos);
581
- vert.setColor(colorFromVector4(initColor));
582
- });
583
- this.vertices.splice(vertices.length, this.vertices.length);
562
+ initColor.r += colorChanges[i].r;
563
+ initColor.g += colorChanges[i].g;
564
+ initColor.b += colorChanges[i].b;
565
+ initColor.a += colorChanges[i].a;
566
+ vert.set(initPos);
567
+ currentColor.setValues(initColor);
568
+ }
569
+ oldVertices.splice(newVertices.length, oldVertices.length);
570
+ oldColors.splice(newColors.length, oldColors.length);
584
571
  this.vertexCache.updated();
585
572
  }, t, f);
586
573
  }
@@ -590,12 +577,12 @@ export class Line3d extends SimulationElement3d {
590
577
  to;
591
578
  thickness;
592
579
  constructor(pos, to, thickness) {
593
- super(pos.getPos(), vector3(), to.getColor() || undefined);
580
+ super(pos.getPos(), vector3(), to.getColor() ?? undefined);
594
581
  this.thickness = thickness;
595
582
  this.to = to.getPos();
596
583
  vec3.scale(this.to, devicePixelRatio, this.to);
597
584
  vec3.sub(this.to, this.pos, this.to);
598
- this.geometry = new Line3dGeometry(this.pos, this.to, this.thickness, pos.getColor() || this.getColor(), to.getColor());
585
+ this.geometry = new Line3dGeometry(this.pos, this.to, this.thickness);
599
586
  }
600
587
  setStart(pos, t = 0, f) {
601
588
  return this.moveTo(pos, t, f);
@@ -621,11 +608,11 @@ export class Line2d extends SimulationElement2d {
621
608
  to;
622
609
  thickness;
623
610
  constructor(from, to, thickness = 1) {
624
- super(vector2FromVector3(from.getPos()), vector3(), from.getColor() || undefined);
611
+ super(vector2FromVector3(from.getPos()), vector3(), from.getColor() ?? undefined);
625
612
  this.thickness = thickness * devicePixelRatio;
626
613
  this.to = to.getPos();
627
614
  vec2.sub(this.to, this.pos, this.to);
628
- this.geometry = new Line2dGeometry(this.pos, this.to, this.thickness, from.getColor() || this.getColor(), to.getColor());
615
+ this.geometry = new Line2dGeometry(this.pos, this.to, this.thickness);
629
616
  }
630
617
  setStart(pos, t = 0, f) {
631
618
  return this.moveTo(pos, t, f);
@@ -792,7 +779,7 @@ export class CubicBezierCurve2d extends BezierCurve2d {
792
779
  constructor(points, detail, colors) {
793
780
  super(points);
794
781
  this.detail = detail;
795
- this.colors = colors || [];
782
+ this.colors = colors ?? [];
796
783
  }
797
784
  getDetail() {
798
785
  return this.detail;
@@ -836,7 +823,7 @@ export class SplinePoint2d {
836
823
  if (prevColor) {
837
824
  colors[0] = prevColor;
838
825
  }
839
- else if (this.start && this.start.getColor()) {
826
+ else if (this.start?.getColor()) {
840
827
  colors[0] = this.start.getColor();
841
828
  }
842
829
  if (this.end.getColor()) {
@@ -848,7 +835,7 @@ export class SplinePoint2d {
848
835
  return colors;
849
836
  }
850
837
  getVectorArray(prevEnd, prevControl) {
851
- const firstControl = cloneBuf(this.control1 || prevControl || vector2());
838
+ const firstControl = cloneBuf(this.control1 ?? prevControl ?? vector2());
852
839
  if (prevEnd) {
853
840
  vec2.add(firstControl, prevEnd, firstControl);
854
841
  }
@@ -875,15 +862,55 @@ export class Spline2d extends SimulationElement2d {
875
862
  length;
876
863
  constructor(pos, points, thickness = devicePixelRatio, detail = 40) {
877
864
  const tempPos = vector2FromVector3(pos.getPos());
878
- super(tempPos, vector3(), pos.getColor() || undefined);
865
+ super(tempPos, vector3(), pos.getColor() ?? undefined);
879
866
  this.thickness = thickness * devicePixelRatio;
880
867
  this.detail = detail;
881
868
  this.interpolateStart = 0;
882
869
  this.interpolateLimit = 1;
883
870
  this.length = 0;
884
- this.geometry = new Spline2dGeometry(points, this.getColor(), this.thickness, this.detail);
871
+ this.geometry = new Spline2dGeometry(points, this.thickness, this.detail);
872
+ this.material = new VertexColorMaterial();
873
+ this.material.setColor(pos.getColor() ?? color());
874
+ this.setVertexColors();
875
+ this.shader = vertexColorShader;
885
876
  this.estimateLength();
886
877
  }
878
+ setVertexColors() {
879
+ const numVertices = this.geometry.getVertices().length;
880
+ const curves = this.geometry.getCurves();
881
+ const curveVertexIndices = this.geometry.getCurveVertexIndices();
882
+ const vertexInterpolations = this.geometry.getVertexInterpolations();
883
+ const colorArray = Array(numVertices);
884
+ let currentCurveIndex = 0;
885
+ for (let i = 0; i < numVertices / 2; i++) {
886
+ if (i >= curveVertexIndices[currentCurveIndex])
887
+ currentCurveIndex++;
888
+ const curveColors = curves[currentCurveIndex]
889
+ .getColors()
890
+ .map((item) => item ?? this.material.getColor());
891
+ const vertexColor = interpolateColors(curveColors, vertexInterpolations[i]);
892
+ colorArray[i] = vertexColor;
893
+ colorArray[numVertices - i - 1] = vertexColor;
894
+ }
895
+ this.material.setVertexColors(colorArray);
896
+ }
897
+ getVertexBuffer() {
898
+ if (this.vertexCache.shouldUpdate()) {
899
+ this.setVertexColors();
900
+ }
901
+ return super.getVertexBuffer();
902
+ }
903
+ isTransparent() {
904
+ const curves = this.geometry.getCurves();
905
+ for (let i = 0; i < curves.length; i++) {
906
+ const colors = curves[i].getColors();
907
+ for (let j = 0; j < colors.length; j++) {
908
+ if (colors[j]?.isTransparent())
909
+ return true;
910
+ }
911
+ }
912
+ return false;
913
+ }
887
914
  estimateLength() {
888
915
  this.length = 0;
889
916
  const curves = this.geometry.getCurves();
@@ -925,9 +952,9 @@ export class Spline2d extends SimulationElement2d {
925
952
  }
926
953
  updatePointAbsolute(pointIndex, newPoint) {
927
954
  const clonePoint = newPoint.clone();
928
- const start = clonePoint.getStart()?.getPos() || vector3();
955
+ const start = clonePoint.getStart()?.getPos() ?? vector3();
929
956
  const end = clonePoint.getEnd().getPos();
930
- const pos = this.getPos();
957
+ const pos = this.getRelativePos();
931
958
  vec3.sub(start, pos, start);
932
959
  vec3.sub(end, pos, end);
933
960
  this.geometry.updatePoint(pointIndex, clonePoint);
@@ -985,7 +1012,7 @@ export class Instance extends SimulationElement3d {
985
1012
  super(vector3(), vector3());
986
1013
  // 32 matrices
987
1014
  this.maxInstances = 32;
988
- this.matrixBuffer = null;
1015
+ this.matrixBuffer = new MemoBuffer(GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST, this.maxInstances * mat4ByteLength);
989
1016
  obj.isInstanced = true;
990
1017
  this.obj = obj;
991
1018
  this.instanceMatrix = [];
@@ -998,12 +1025,12 @@ export class Instance extends SimulationElement3d {
998
1025
  this.instanceMatrix.push(clone);
999
1026
  }
1000
1027
  }
1001
- setNumInstances(numInstances) {
1028
+ setNumInstances(numInstances, forceResizeBuffer = false) {
1002
1029
  if (numInstances < 0)
1003
1030
  throw logger.error('Num instances is less than 0');
1004
- if (numInstances > this.maxInstances) {
1031
+ if (numInstances > this.maxInstances || forceResizeBuffer) {
1005
1032
  this.maxInstances = numInstances;
1006
- this.allocBuffer(numInstances);
1033
+ this.matrixBuffer.setSize(numInstances * mat4ByteLength);
1007
1034
  }
1008
1035
  const oldLen = this.instanceMatrix.length;
1009
1036
  if (numInstances < oldLen) {
@@ -1029,37 +1056,23 @@ export class Instance extends SimulationElement3d {
1029
1056
  const device = globalInfo.getDevice();
1030
1057
  if (!device)
1031
1058
  return;
1032
- if (!this.matrixBuffer) {
1033
- const minSize = this.maxInstances * mat4ByteLength;
1034
- const size = Math.max(minSize, this.instanceMatrix.length);
1035
- this.allocBuffer(size);
1036
- }
1059
+ // this.allocBuffer(size);
1060
+ const gpuBuffer = this.matrixBuffer.getBuffer();
1037
1061
  const buf = new Float32Array(transformation);
1038
- device.queue.writeBuffer(this.matrixBuffer, instance * mat4ByteLength, buf.buffer, buf.byteOffset, buf.byteLength);
1039
- this.matrixBuffer.unmap();
1040
- }
1041
- allocBuffer(size) {
1042
- const device = globalInfo.getDevice();
1043
- if (!device)
1044
- return;
1045
- const byteSize = size * mat4ByteLength;
1046
- this.matrixBuffer = device.createBuffer({
1047
- size: byteSize,
1048
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
1049
- });
1062
+ device.queue.writeBuffer(gpuBuffer, instance * mat4ByteLength, buf.buffer, buf.byteOffset, buf.byteLength);
1063
+ gpuBuffer.unmap();
1050
1064
  }
1051
1065
  mapBuffer() {
1052
1066
  const device = globalInfo.getDevice();
1053
1067
  if (!device)
1054
1068
  return;
1055
- if (!this.matrixBuffer) {
1056
- const minSize = this.maxInstances * mat4ByteLength;
1057
- const size = Math.max(minSize, this.instanceMatrix.length);
1058
- this.allocBuffer(size);
1059
- }
1069
+ const minSize = this.maxInstances * mat4ByteLength;
1070
+ const size = Math.max(minSize, this.instanceMatrix.length);
1071
+ this.matrixBuffer.setSize(size);
1072
+ const gpuBuffer = this.matrixBuffer.getBuffer();
1060
1073
  const buf = new Float32Array(this.instanceMatrix.map((mat) => [...mat]).flat());
1061
- device.queue.writeBuffer(this.matrixBuffer, 0, buf.buffer, buf.byteOffset, buf.byteLength);
1062
- this.matrixBuffer.unmap();
1074
+ device.queue.writeBuffer(gpuBuffer, 0, buf.buffer, buf.byteOffset, buf.byteLength);
1075
+ gpuBuffer.unmap();
1063
1076
  this.hasMapped = true;
1064
1077
  }
1065
1078
  getInstances() {
@@ -1068,20 +1081,26 @@ export class Instance extends SimulationElement3d {
1068
1081
  getNumInstances() {
1069
1082
  return this.instanceMatrix.length;
1070
1083
  }
1071
- getMatrixBuffer() {
1084
+ getInstanceBuffer() {
1072
1085
  if (!this.hasMapped) {
1073
1086
  this.mapBuffer();
1074
1087
  }
1075
- return this.matrixBuffer;
1088
+ return this.matrixBuffer.getBuffer();
1076
1089
  }
1077
1090
  getVertexCount() {
1078
1091
  return this.obj.getVertexCount();
1079
1092
  }
1080
- getGeometryType() {
1081
- return this.obj.getGeometryType();
1093
+ getIndexCount() {
1094
+ return this.obj.getIndexCount();
1095
+ }
1096
+ getGeometryTopology() {
1097
+ return this.obj.getGeometryTopology();
1098
+ }
1099
+ getVertexBuffer() {
1100
+ return this.obj.getVertexBuffer();
1082
1101
  }
1083
- getBuffer() {
1084
- return this.obj.getBuffer();
1102
+ getIndexBuffer() {
1103
+ return this.obj.getIndexBuffer();
1085
1104
  }
1086
1105
  getModelMatrix() {
1087
1106
  return this.obj.getModelMatrix();
@@ -1093,9 +1112,11 @@ export class TraceLines2d extends SimulationElement2d {
1093
1112
  super(vector2(), vector3(), color);
1094
1113
  this.geometry = new TraceLinesGeometry(maxLen);
1095
1114
  }
1096
- addPoint(point, color) {
1097
- const vert = vertex(point[0], point[1], point?.[2] || 0, color);
1098
- this.geometry.addVertex(vert);
1115
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1116
+ addPoint(vert, _color) {
1117
+ const newVert = vert.length < 3 ? vector3(vert[0] ?? 0, vert[1] ?? 0, 0) : vert;
1118
+ // const vert = vertex(point[0], point[1], point?.[2] || 0, color);
1119
+ this.geometry.addVertex(newVert);
1099
1120
  this.vertexCache.updated();
1100
1121
  }
1101
1122
  // always being wireframe means that triangleOrder
@@ -1111,9 +1132,11 @@ export class TraceLines3d extends SimulationElement3d {
1111
1132
  super(vector3(), vector3(), color);
1112
1133
  this.geometry = new TraceLinesGeometry(maxLen);
1113
1134
  }
1114
- addPoint(point, color) {
1115
- const vert = vertex(point[0], point[1], point?.[2] || 0, color);
1116
- this.geometry.addVertex(vert);
1135
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1136
+ addPoint(vert, _color) {
1137
+ // const vert = vertex(point[0], point[1], point?.[2] || 0, color);
1138
+ const newVert = vert.length < 3 ? vector3(vert[0] ?? 0, vert[1] ?? 0, 0) : vert;
1139
+ this.geometry.addVertex(newVert);
1117
1140
  this.vertexCache.updated();
1118
1141
  }
1119
1142
  // always being wireframe means that triangleOrder