simulationjsv2 0.7.4 → 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,17 +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
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';
7
10
  export class SimulationElement3d {
8
11
  children;
9
12
  uniformBuffer;
13
+ prevInfo;
14
+ pipeline;
15
+ shader;
16
+ material;
17
+ cullMode;
10
18
  parent;
11
19
  centerOffset;
12
- rotationOffset;
13
20
  pos;
14
- color;
15
21
  wireframe;
16
22
  vertexCache;
17
23
  rotation;
@@ -24,19 +30,20 @@ export class SimulationElement3d {
24
30
  * @param pos - Expected to be adjusted to devicePixelRatio before reaching constructor
25
31
  */
26
32
  constructor(pos, rotation, color = new Color()) {
27
- const uniformBufferSize = mat4ByteLength * 2 + 4 * 2 + 8; // 4x4 matrix * 2 + vec2<f32> + 8 bc 144 is cool
28
33
  this.pos = pos;
29
34
  this.centerOffset = vector3();
30
- // TODO test this
31
- this.rotationOffset = vector3();
32
- this.color = color;
33
- this.vertexCache = new VertexCache();
35
+ this.vertexCache = new Float32ArrayCache();
34
36
  this.wireframe = false;
35
37
  this.rotation = cloneBuf(rotation);
36
38
  this.uniformBuffer = new MemoBuffer(GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, uniformBufferSize);
37
39
  this.children = [];
38
40
  this.modelMatrix = matrix4();
39
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';
40
47
  }
41
48
  add(el, id) {
42
49
  el.setParent(this);
@@ -65,11 +72,20 @@ export class SimulationElement3d {
65
72
  getParent() {
66
73
  return this.parent;
67
74
  }
75
+ getCullMode() {
76
+ return this.cullMode;
77
+ }
78
+ setCullMode(mode) {
79
+ this.cullMode = mode;
80
+ }
68
81
  setCenterOffset(offset) {
69
82
  this.centerOffset = offset;
70
83
  }
71
- setRotationOffset(offset) {
72
- this.rotationOffset = offset;
84
+ getShader() {
85
+ return this.shader;
86
+ }
87
+ setShader(shader) {
88
+ this.shader = shader;
73
89
  }
74
90
  resetCenterOffset() {
75
91
  this.centerOffset[0] = 0;
@@ -81,14 +97,31 @@ export class SimulationElement3d {
81
97
  return this.modelMatrix;
82
98
  }
83
99
  isTransparent() {
84
- return this.color.a < 1;
100
+ return this.material.isTransparent();
85
101
  }
86
- getUniformBuffer(mat) {
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();
87
111
  const device = globalInfo.errorGetDevice();
88
112
  const buffer = this.uniformBuffer.getBuffer();
89
113
  device.queue.writeBuffer(buffer, modelProjMatOffset, mat);
90
114
  return buffer;
91
115
  }
116
+ getPipeline() {
117
+ const device = globalInfo.errorGetDevice();
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;
122
+ }
123
+ return this.pipeline;
124
+ }
92
125
  mirrorParentTransforms3d(mat) {
93
126
  if (!this.parent)
94
127
  return;
@@ -105,12 +138,9 @@ export class SimulationElement3d {
105
138
  this.mirrorParentTransforms3d(this.modelMatrix);
106
139
  }
107
140
  mat4.translate(this.modelMatrix, this.pos, this.modelMatrix);
108
- // vec3.negate(this.rotationOffset, cachedVec1);
109
- // mat4.translate(this.modelMatrix, cachedVec1, this.modelMatrix);
110
141
  mat4.rotateZ(this.modelMatrix, this.rotation[2], this.modelMatrix);
111
142
  mat4.rotateY(this.modelMatrix, this.rotation[1], this.modelMatrix);
112
143
  mat4.rotateX(this.modelMatrix, this.rotation[0], this.modelMatrix);
113
- // mat4.translate(this.modelMatrix, this.rotationOffset, this.modelMatrix);
114
144
  mat4.translate(this.modelMatrix, this.centerOffset, this.modelMatrix);
115
145
  }
116
146
  mirrorParentTransforms2d(mat) {
@@ -134,11 +164,13 @@ export class SimulationElement3d {
134
164
  else {
135
165
  mat4.translate(this.modelMatrix, pos, this.modelMatrix);
136
166
  }
167
+ const negated = vec3.negate(this.centerOffset);
168
+ mat4.translate(this.modelMatrix, negated, this.modelMatrix);
137
169
  mat4.rotateZ(this.modelMatrix, this.rotation[2], this.modelMatrix);
138
170
  mat4.translate(this.modelMatrix, this.centerOffset, this.modelMatrix);
139
171
  }
140
- getGeometryType() {
141
- return this.geometry.getType();
172
+ getGeometryTopology() {
173
+ return this.geometry.getTopology();
142
174
  }
143
175
  setWireframe(wireframe) {
144
176
  this.wireframe = wireframe;
@@ -146,8 +178,8 @@ export class SimulationElement3d {
146
178
  isWireframe() {
147
179
  return this.wireframe;
148
180
  }
149
- getColor() {
150
- return this.color;
181
+ getMaterial() {
182
+ return this.material;
151
183
  }
152
184
  getRelativePos() {
153
185
  return this.pos;
@@ -165,16 +197,17 @@ export class SimulationElement3d {
165
197
  return this.centerOffset;
166
198
  }
167
199
  fill(newColor, t = 0, f) {
168
- const diff = newColor.diff(this.color);
200
+ const materialColor = this.material.getColor();
201
+ const diff = newColor.diff(materialColor);
169
202
  const finalColor = newColor.clone();
170
203
  return internalTransitionValues((p) => {
171
- this.color.r += diff.r * p;
172
- this.color.g += diff.g * p;
173
- this.color.b += diff.b * p;
174
- 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;
175
208
  this.vertexCache.updated();
176
209
  }, () => {
177
- this.color = finalColor;
210
+ this.material.setColor(finalColor);
178
211
  this.vertexCache.updated();
179
212
  }, t, f);
180
213
  }
@@ -252,38 +285,41 @@ export class SimulationElement3d {
252
285
  if (this.vertexCache.shouldUpdate()) {
253
286
  this.geometry.recompute();
254
287
  }
255
- let childrenVertices = 0;
288
+ let vertexCount = this.geometry.getIndexes(this.isWireframe()).length;
256
289
  for (let i = 0; i < this.children.length; i++) {
257
- childrenVertices += this.children[i].getObj().getVertexCount();
258
- }
259
- let currentVertices = 0;
260
- if (this.isWireframe()) {
261
- currentVertices = this.geometry.getWireframeVertexCount();
290
+ vertexCount += this.children[i].getObj().getVertexCount();
262
291
  }
263
- else {
264
- 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();
265
298
  }
266
- return currentVertices + childrenVertices;
299
+ return indexCount;
267
300
  }
268
- getBuffer(vertexParamGenerator) {
301
+ writeBuffers() {
302
+ this.shader.writeBuffers(this);
303
+ }
304
+ getVertexBuffer() {
269
305
  if (this.vertexCache.shouldUpdate()) {
270
306
  this.geometry.recompute();
271
- if (this.isInstanced) {
272
- bufferGenerator.setInstancing(true);
273
- }
274
- let resBuffer;
275
- if (this.isWireframe()) {
276
- resBuffer = this.geometry.getWireframeBuffer(this.color, vertexParamGenerator);
277
- }
278
- else {
279
- resBuffer = this.geometry.getTriangleBuffer(this.color, vertexParamGenerator);
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);
280
313
  }
281
- bufferGenerator.setInstancing(false);
282
- this.vertexCache.setCache(resBuffer);
283
- return resBuffer;
314
+ this.vertexCache.setCache(vertexBuffer);
315
+ return vertexBuffer;
284
316
  }
285
317
  return this.vertexCache.getCache();
286
318
  }
319
+ getIndexBuffer() {
320
+ const order = this.geometry.getIndexes(this.isWireframe());
321
+ return new Uint32Array(order);
322
+ }
287
323
  }
288
324
  export class EmptyElement extends SimulationElement3d {
289
325
  geometry = new BlankGeometry();
@@ -291,7 +327,7 @@ export class EmptyElement extends SimulationElement3d {
291
327
  isEmpty = true;
292
328
  constructor(label) {
293
329
  super(vector3(), vector3());
294
- this.label = label || null;
330
+ this.label = label ?? null;
295
331
  }
296
332
  getLabel() {
297
333
  return this.label;
@@ -322,6 +358,7 @@ export class Plane extends SimulationElement3d {
322
358
  this.rotation = rotation;
323
359
  this.points = points;
324
360
  this.geometry = new PlaneGeometry(points);
361
+ this.cullMode = 'none';
325
362
  }
326
363
  setPoints(newPoints) {
327
364
  this.points = newPoints;
@@ -332,70 +369,21 @@ export class Square extends SimulationElement2d {
332
369
  geometry;
333
370
  width;
334
371
  height;
335
- vertexColors;
336
372
  /**
337
373
  * @param centerOffset{Vector2} - A vector2 of values from 0 to 1
338
374
  * @param vertexColors{Record<number, Color>} - 0 is top left vertex, numbers increase clockwise
339
375
  */
340
- constructor(pos, width, height, color, rotation, centerOffset, vertexColors) {
376
+ constructor(pos, width, height, color, rotation) {
341
377
  super(pos, vector3(0, 0, rotation), color);
342
- this.width = width * devicePixelRatio;
343
- this.height = height * devicePixelRatio;
344
- this.vertexColors = this.cloneColorMap(vertexColors || {});
345
- this.geometry = new SquareGeometry(this.width, this.height, centerOffset);
346
- this.geometry.setVertexColorMap(this.vertexColors);
347
- }
348
- setOffset(offset) {
349
- this.geometry.setOffset(offset);
350
- }
351
- setOffsetInplace(offset) {
352
- const diff = vector3FromVector2(offset);
353
- vec2.sub(diff, this.geometry.getOffset(), diff);
354
- vec2.mul(diff, vector2(this.width / devicePixelRatio, -this.height / devicePixelRatio), diff);
355
- this.setOffset(offset);
356
- this.move(diff);
357
- }
358
- cloneColorMap(colorMap) {
359
- const newColorMap = {};
360
- Object.entries(colorMap).forEach(([key, value]) => {
361
- newColorMap[+key] = value.clone();
362
- });
363
- return newColorMap;
364
- }
365
- setVertexColors(newColorMap, t = 0, f) {
366
- const colorMap = this.cloneColorMap(newColorMap);
367
- const diffMap = {};
368
- Object.entries(colorMap).forEach(([key, value]) => {
369
- if (!this.vertexColors[+key]) {
370
- this.vertexColors[+key] = color();
371
- }
372
- diffMap[+key] = value.diff(this.vertexColors[+key] || color());
373
- });
374
- Object.entries(this.vertexColors).forEach(([key, value]) => {
375
- if (!diffMap[+key]) {
376
- const clone = value.clone();
377
- clone.r *= -1;
378
- clone.g *= -1;
379
- clone.b *= -1;
380
- diffMap[+key] = clone;
381
- }
382
- });
383
- return internalTransitionValues((p) => {
384
- Object.entries(diffMap).forEach(([key, value]) => {
385
- const color = this.vertexColors[+key];
386
- color.r += value.r * p;
387
- color.g += value.g * p;
388
- color.b += value.b * p;
389
- color.a += value.a * p;
390
- this.vertexColors[+key] = color;
391
- });
392
- this.geometry.setVertexColorMap(this.vertexColors);
393
- this.vertexCache.updated();
394
- }, () => {
395
- this.vertexColors = colorMap;
396
- this.geometry.setVertexColorMap(this.vertexColors);
397
- this.vertexCache.updated();
398
- }, 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;
399
387
  }
400
388
  scaleWidth(amount, t = 0, f) {
401
389
  const finalWidth = this.width * amount;
@@ -508,78 +496,78 @@ export class Circle extends SimulationElement2d {
508
496
  }
509
497
  export class Polygon extends SimulationElement2d {
510
498
  geometry;
511
- vertices;
512
- constructor(pos, points, color, rotation) {
499
+ constructor(pos, vertices, color, rotation) {
513
500
  super(pos, vector3(0, 0, rotation), color);
514
- this.vertices = points;
515
- 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);
516
509
  }
517
510
  getVertices() {
518
- return this.vertices;
519
- }
520
- setVertices(newVertices, t = 0, f) {
521
- const vertices = newVertices.map((vert) => {
522
- const newVertex = vert.clone();
523
- newVertex.setZ(0);
524
- 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;
525
530
  });
526
- const lastVert = this.vertices.length > 0 ? this.vertices[this.vertices.length - 1] : vertex(0, 0, 0, color());
527
- if (vertices.length > this.vertices.length) {
528
- while (vertices.length > this.vertices.length) {
529
- const lastPos = lastVert.getPos();
530
- this.vertices.push(new Vertex(lastPos[0], lastPos[1], 0, lastVert.getColor() || this.color));
531
- }
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]));
532
540
  }
533
- const initialPositions = this.vertices.map((p) => cloneBuf(p.getPos()));
534
- const posChanges = [
535
- ...vertices.map((vert, i) => {
536
- const vec = vector3();
537
- vec3.sub(vert.getPos(), this.vertices[i].getPos(), vec);
538
- return cloneBuf(vec);
539
- }),
540
- ...(this.vertices.length > vertices.length
541
- ? this.vertices.slice(vertices.length, this.vertices.length).map((vert) => {
542
- const vec = cloneBuf(vertices[vertices.length - 1].getPos());
543
- vec3.sub(vec, vert.getPos(), vec);
544
- return vec;
545
- })
546
- : [])
547
- ];
548
- const initialColors = this.vertices.map((vert) => (vert.getColor() || this.color).toVec4());
549
- const colorChanges = [
550
- ...vertices.map((vert, i) => {
551
- const diff = (vert.getColor() || this.color).diff(this.vertices[i].getColor() || this.color);
552
- return diff.toVec4();
553
- }),
554
- ...(this.vertices.length > vertices.length
555
- ? this.vertices.slice(vertices.length, this.vertices.length).map((vert) => {
556
- const toColor = vertices[vertices.length - 1].getColor();
557
- return (toColor || this.color).diff(vert.getColor() || this.color).toVec4();
558
- })
559
- : [])
560
- ];
561
541
  return internalTransitionValues((p) => {
562
- this.vertices.forEach((vert, i) => {
542
+ for (let i = 0; i < oldVertices.length; i++) {
543
+ const vert = oldVertices[i];
544
+ const currentColor = oldColors[i];
563
545
  const posChange = cloneBuf(posChanges[i]);
564
- const colorChange = cloneBuf(colorChanges[i]);
546
+ const colorChange = colorChanges[i].clone();
565
547
  vec3.scale(posChange, p, posChange);
566
- vec3.add(vert.getPos(), posChange, posChange);
567
- vec4.scale(colorChange, p, colorChange);
568
- vec4.add((vert.getColor() || this.color).toVec4(), colorChange, colorChange);
569
- vert.setPos(posChange);
570
- vert.setColor(colorFromVector4(colorChange));
571
- });
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
+ }
572
554
  this.vertexCache.updated();
573
555
  }, () => {
574
- this.vertices.forEach((vert, i) => {
556
+ for (let i = 0; i < oldVertices.length; i++) {
557
+ const vert = oldVertices[i];
558
+ const currentColor = oldColors[i];
575
559
  const initPos = initialPositions[i];
576
560
  const initColor = initialColors[i];
577
561
  vec3.add(initPos, posChanges[i], initPos);
578
- vec4.add(initColor, colorChanges[i], initColor);
579
- vert.setPos(initPos);
580
- vert.setColor(colorFromVector4(initColor));
581
- });
582
- 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);
583
571
  this.vertexCache.updated();
584
572
  }, t, f);
585
573
  }
@@ -589,12 +577,12 @@ export class Line3d extends SimulationElement3d {
589
577
  to;
590
578
  thickness;
591
579
  constructor(pos, to, thickness) {
592
- super(pos.getPos(), vector3(), to.getColor() || undefined);
580
+ super(pos.getPos(), vector3(), to.getColor() ?? undefined);
593
581
  this.thickness = thickness;
594
582
  this.to = to.getPos();
595
583
  vec3.scale(this.to, devicePixelRatio, this.to);
596
584
  vec3.sub(this.to, this.pos, this.to);
597
- 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);
598
586
  }
599
587
  setStart(pos, t = 0, f) {
600
588
  return this.moveTo(pos, t, f);
@@ -620,11 +608,11 @@ export class Line2d extends SimulationElement2d {
620
608
  to;
621
609
  thickness;
622
610
  constructor(from, to, thickness = 1) {
623
- super(vector2FromVector3(from.getPos()), vector3(), from.getColor() || undefined);
611
+ super(vector2FromVector3(from.getPos()), vector3(), from.getColor() ?? undefined);
624
612
  this.thickness = thickness * devicePixelRatio;
625
613
  this.to = to.getPos();
626
614
  vec2.sub(this.to, this.pos, this.to);
627
- 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);
628
616
  }
629
617
  setStart(pos, t = 0, f) {
630
618
  return this.moveTo(pos, t, f);
@@ -791,7 +779,7 @@ export class CubicBezierCurve2d extends BezierCurve2d {
791
779
  constructor(points, detail, colors) {
792
780
  super(points);
793
781
  this.detail = detail;
794
- this.colors = colors || [];
782
+ this.colors = colors ?? [];
795
783
  }
796
784
  getDetail() {
797
785
  return this.detail;
@@ -835,7 +823,7 @@ export class SplinePoint2d {
835
823
  if (prevColor) {
836
824
  colors[0] = prevColor;
837
825
  }
838
- else if (this.start && this.start.getColor()) {
826
+ else if (this.start?.getColor()) {
839
827
  colors[0] = this.start.getColor();
840
828
  }
841
829
  if (this.end.getColor()) {
@@ -847,7 +835,7 @@ export class SplinePoint2d {
847
835
  return colors;
848
836
  }
849
837
  getVectorArray(prevEnd, prevControl) {
850
- const firstControl = cloneBuf(this.control1 || prevControl || vector2());
838
+ const firstControl = cloneBuf(this.control1 ?? prevControl ?? vector2());
851
839
  if (prevEnd) {
852
840
  vec2.add(firstControl, prevEnd, firstControl);
853
841
  }
@@ -874,21 +862,50 @@ export class Spline2d extends SimulationElement2d {
874
862
  length;
875
863
  constructor(pos, points, thickness = devicePixelRatio, detail = 40) {
876
864
  const tempPos = vector2FromVector3(pos.getPos());
877
- super(tempPos, vector3(), pos.getColor() || undefined);
865
+ super(tempPos, vector3(), pos.getColor() ?? undefined);
878
866
  this.thickness = thickness * devicePixelRatio;
879
867
  this.detail = detail;
880
868
  this.interpolateStart = 0;
881
869
  this.interpolateLimit = 1;
882
870
  this.length = 0;
883
- 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;
884
876
  this.estimateLength();
885
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
+ }
886
903
  isTransparent() {
887
904
  const curves = this.geometry.getCurves();
888
905
  for (let i = 0; i < curves.length; i++) {
889
906
  const colors = curves[i].getColors();
890
907
  for (let j = 0; j < colors.length; j++) {
891
- if (colors[j]?.a ?? 0 < 1)
908
+ if (colors[j]?.isTransparent())
892
909
  return true;
893
910
  }
894
911
  }
@@ -935,7 +952,7 @@ export class Spline2d extends SimulationElement2d {
935
952
  }
936
953
  updatePointAbsolute(pointIndex, newPoint) {
937
954
  const clonePoint = newPoint.clone();
938
- const start = clonePoint.getStart()?.getPos() || vector3();
955
+ const start = clonePoint.getStart()?.getPos() ?? vector3();
939
956
  const end = clonePoint.getEnd().getPos();
940
957
  const pos = this.getRelativePos();
941
958
  vec3.sub(start, pos, start);
@@ -1045,15 +1062,6 @@ export class Instance extends SimulationElement3d {
1045
1062
  device.queue.writeBuffer(gpuBuffer, instance * mat4ByteLength, buf.buffer, buf.byteOffset, buf.byteLength);
1046
1063
  gpuBuffer.unmap();
1047
1064
  }
1048
- // private allocBuffer(size: number) {
1049
- // const device = globalInfo.getDevice();
1050
- // if (!device) return;
1051
- // const byteSize = size * mat4ByteLength;
1052
- // this.matrixBuffer = device.createBuffer({
1053
- // size: byteSize,
1054
- // usage:
1055
- // });
1056
- // }
1057
1065
  mapBuffer() {
1058
1066
  const device = globalInfo.getDevice();
1059
1067
  if (!device)
@@ -1073,7 +1081,7 @@ export class Instance extends SimulationElement3d {
1073
1081
  getNumInstances() {
1074
1082
  return this.instanceMatrix.length;
1075
1083
  }
1076
- getMatrixBuffer() {
1084
+ getInstanceBuffer() {
1077
1085
  if (!this.hasMapped) {
1078
1086
  this.mapBuffer();
1079
1087
  }
@@ -1082,11 +1090,17 @@ export class Instance extends SimulationElement3d {
1082
1090
  getVertexCount() {
1083
1091
  return this.obj.getVertexCount();
1084
1092
  }
1085
- getGeometryType() {
1086
- 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();
1087
1101
  }
1088
- getBuffer() {
1089
- return this.obj.getBuffer();
1102
+ getIndexBuffer() {
1103
+ return this.obj.getIndexBuffer();
1090
1104
  }
1091
1105
  getModelMatrix() {
1092
1106
  return this.obj.getModelMatrix();
@@ -1098,9 +1112,11 @@ export class TraceLines2d extends SimulationElement2d {
1098
1112
  super(vector2(), vector3(), color);
1099
1113
  this.geometry = new TraceLinesGeometry(maxLen);
1100
1114
  }
1101
- addPoint(point, color) {
1102
- const vert = vertex(point[0], point[1], point?.[2] || 0, color);
1103
- 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);
1104
1120
  this.vertexCache.updated();
1105
1121
  }
1106
1122
  // always being wireframe means that triangleOrder
@@ -1116,9 +1132,11 @@ export class TraceLines3d extends SimulationElement3d {
1116
1132
  super(vector3(), vector3(), color);
1117
1133
  this.geometry = new TraceLinesGeometry(maxLen);
1118
1134
  }
1119
- addPoint(point, color) {
1120
- const vert = vertex(point[0], point[1], point?.[2] || 0, color);
1121
- 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);
1122
1140
  this.vertexCache.updated();
1123
1141
  }
1124
1142
  // always being wireframe means that triangleOrder
package/dist/index.d.ts CHANGED
@@ -2,4 +2,6 @@ export * from './simulation.js';
2
2
  export * from './graphics.js';
3
3
  export * from './utils.js';
4
4
  export * from './types.js';
5
+ export * from './shaders.js';
6
+ export * from './materials.js';
5
7
  export { vec2, vec3, vec4, mat3, mat4 } from 'wgpu-matrix';