q5 4.2.6 → 4.4.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/deno.json +1 -1
- package/package.json +1 -1
- package/q5.d.ts +50 -16
- package/q5.js +460 -125
- package/q5.min.js +2 -2
package/q5.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* q5.js
|
|
3
|
-
* @version 4.
|
|
3
|
+
* @version 4.4
|
|
4
4
|
* @author quinton-ashley
|
|
5
5
|
* @contributors evanalulu, Tezumie, ormaq, Dukemz, LingDong-
|
|
6
6
|
* @license LGPL-3.0
|
|
@@ -487,11 +487,10 @@ if (typeof window == 'object') {
|
|
|
487
487
|
}
|
|
488
488
|
};
|
|
489
489
|
|
|
490
|
-
window.addEventListener('beforeunload', cleanup);
|
|
491
490
|
window.addEventListener('pagehide', cleanup);
|
|
492
491
|
} else global.window = 0;
|
|
493
492
|
|
|
494
|
-
Q5.version = Q5.VERSION = '4.
|
|
493
|
+
Q5.version = Q5.VERSION = '4.4';
|
|
495
494
|
|
|
496
495
|
if (typeof document == 'object') {
|
|
497
496
|
document.addEventListener('DOMContentLoaded', () => {
|
|
@@ -3556,18 +3555,16 @@ Q5.modules.input = ($, q) => {
|
|
|
3556
3555
|
};
|
|
3557
3556
|
|
|
3558
3557
|
$._updatePointer = (e) => {
|
|
3559
|
-
let id = e.pointerId
|
|
3560
|
-
if (id == undefined) {
|
|
3561
|
-
if (e instanceof MouseEvent) id = 0;
|
|
3562
|
-
else return;
|
|
3563
|
-
}
|
|
3558
|
+
let id = e.pointerId ?? $.pointers[0]?.id;
|
|
3564
3559
|
|
|
3565
3560
|
let p = $.pointers.find((p) => p.id === id);
|
|
3566
3561
|
if (!p) {
|
|
3567
3562
|
p = { id };
|
|
3568
|
-
$.pointers.push(p);
|
|
3563
|
+
if (e.type != 'wheel') $.pointers.push(p);
|
|
3569
3564
|
}
|
|
3570
|
-
|
|
3565
|
+
|
|
3566
|
+
if (e.type != 'wheel') p.event = e;
|
|
3567
|
+
else $._wheel = p;
|
|
3571
3568
|
|
|
3572
3569
|
let x, y;
|
|
3573
3570
|
if (c) {
|
|
@@ -3595,16 +3592,19 @@ Q5.modules.input = ($, q) => {
|
|
|
3595
3592
|
|
|
3596
3593
|
$._updateMouse = (e) => {
|
|
3597
3594
|
let p = $.pointers[0];
|
|
3598
|
-
if (e.pointerId != undefined && e.pointerId != p.id) return;
|
|
3599
3595
|
|
|
3600
3596
|
if (document.pointerLockElement) {
|
|
3601
3597
|
if (e.movementX != undefined) {
|
|
3602
3598
|
q.mouseX += e.movementX;
|
|
3603
3599
|
q.mouseY += e.movementY;
|
|
3604
3600
|
}
|
|
3605
|
-
} else {
|
|
3601
|
+
} else if (p) {
|
|
3602
|
+
if (e.pointerId != undefined && e.pointerId != p.id) return;
|
|
3606
3603
|
q.mouseX = p.canvasPos?.x ?? p.x;
|
|
3607
3604
|
q.mouseY = p.canvasPos?.y ?? p.y;
|
|
3605
|
+
} else if ($._wheel) {
|
|
3606
|
+
q.mouseX = $._wheel.x;
|
|
3607
|
+
q.mouseY = $._wheel.y;
|
|
3608
3608
|
}
|
|
3609
3609
|
|
|
3610
3610
|
if (e.movementX != undefined) {
|
|
@@ -3635,15 +3635,16 @@ Q5.modules.input = ($, q) => {
|
|
|
3635
3635
|
|
|
3636
3636
|
$._onpointerup = (e) => {
|
|
3637
3637
|
q.mouseIsPressed = false;
|
|
3638
|
-
if (pressAmt > 0)
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3638
|
+
if (pressAmt > 0) {
|
|
3639
|
+
pressAmt--;
|
|
3640
|
+
$._updatePointer(e);
|
|
3641
|
+
$._updateMouse(e);
|
|
3642
|
+
$.mouseReleased(e);
|
|
3643
|
+
}
|
|
3644
|
+
if (e.pointerType == 'touch' || e.pointerType == 'pen') {
|
|
3643
3645
|
let p = $.pointers.find((p) => p.id === e.pointerId);
|
|
3644
3646
|
if (p) p._ended = true;
|
|
3645
3647
|
}
|
|
3646
|
-
$.mouseReleased(e);
|
|
3647
3648
|
};
|
|
3648
3649
|
|
|
3649
3650
|
$._onclick = (e) => {
|
|
@@ -6152,11 +6153,16 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
|
|
|
6152
6153
|
$.pop();
|
|
6153
6154
|
} else {
|
|
6154
6155
|
addColor(r, g, b, a);
|
|
6155
|
-
let
|
|
6156
|
+
let ci = colorIndex,
|
|
6157
|
+
lx = -c.hw,
|
|
6156
6158
|
rx = c.hw,
|
|
6157
6159
|
ty = -c.hh,
|
|
6158
6160
|
by = c.hh;
|
|
6159
|
-
|
|
6161
|
+
addVert(lx, ty, ci, 0);
|
|
6162
|
+
addVert(rx, ty, ci, 0);
|
|
6163
|
+
addVert(lx, by, ci, 0);
|
|
6164
|
+
addVert(rx, by, ci, 0);
|
|
6165
|
+
drawStack.push(1, 4); // always use the default shapes pipeline
|
|
6160
6166
|
}
|
|
6161
6167
|
};
|
|
6162
6168
|
|
|
@@ -6196,7 +6202,15 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
|
|
|
6196
6202
|
shouldClear = false;
|
|
6197
6203
|
};
|
|
6198
6204
|
|
|
6199
|
-
let transformsBuffer,
|
|
6205
|
+
let transformsBuffer,
|
|
6206
|
+
colorsBuffer,
|
|
6207
|
+
shapesVertBuff,
|
|
6208
|
+
imgVertBuff,
|
|
6209
|
+
polygonVertBuff,
|
|
6210
|
+
polyPtsBuffer,
|
|
6211
|
+
polyPtsBindGroup,
|
|
6212
|
+
charBuffer,
|
|
6213
|
+
textBuffer;
|
|
6200
6214
|
let mainBindGroup, lastTransformsBuffer, lastColorsBuffer;
|
|
6201
6215
|
|
|
6202
6216
|
$._render = () => {
|
|
@@ -6275,6 +6289,37 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
|
|
|
6275
6289
|
|
|
6276
6290
|
// prepare to render images and videos
|
|
6277
6291
|
|
|
6292
|
+
if (polygonVertIdx) {
|
|
6293
|
+
let polygonVertSize = polygonVertIdx * 4; // 4 bytes per float
|
|
6294
|
+
if (!polygonVertBuff || polygonVertBuff.size < polygonVertSize) {
|
|
6295
|
+
if (polygonVertBuff) polygonVertBuff.destroy();
|
|
6296
|
+
polygonVertBuff = Q5.device.createBuffer({
|
|
6297
|
+
size: polygonVertSize * 2,
|
|
6298
|
+
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
|
|
6299
|
+
});
|
|
6300
|
+
}
|
|
6301
|
+
|
|
6302
|
+
Q5.device.queue.writeBuffer(polygonVertBuff, 0, polygonVertStack.subarray(0, polygonVertIdx));
|
|
6303
|
+
$._pass.setVertexBuffer(2, polygonVertBuff);
|
|
6304
|
+
|
|
6305
|
+
if (polyPtsIdx) {
|
|
6306
|
+
let polyPtsSize = polyPtsIdx * 4;
|
|
6307
|
+
if (!polyPtsBuffer || polyPtsBuffer.size < polyPtsSize) {
|
|
6308
|
+
if (polyPtsBuffer) polyPtsBuffer.destroy();
|
|
6309
|
+
polyPtsBuffer = Q5.device.createBuffer({
|
|
6310
|
+
size: Math.max(polyPtsSize * 2, 64),
|
|
6311
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
|
|
6312
|
+
});
|
|
6313
|
+
}
|
|
6314
|
+
Q5.device.queue.writeBuffer(polyPtsBuffer, 0, polyPtsStack.subarray(0, polyPtsIdx));
|
|
6315
|
+
|
|
6316
|
+
polyPtsBindGroup = Q5.device.createBindGroup({
|
|
6317
|
+
layout: polygonBindGroupLayout,
|
|
6318
|
+
entries: [{ binding: 0, resource: { buffer: polyPtsBuffer } }]
|
|
6319
|
+
});
|
|
6320
|
+
}
|
|
6321
|
+
}
|
|
6322
|
+
|
|
6278
6323
|
if (imgVertIdx) {
|
|
6279
6324
|
$._pass.setPipeline($._pipelines[2]); // images pipeline
|
|
6280
6325
|
|
|
@@ -6373,6 +6418,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
|
|
|
6373
6418
|
let drawVertOffset = 0,
|
|
6374
6419
|
imageVertOffset = 0,
|
|
6375
6420
|
textCharOffset = 0,
|
|
6421
|
+
polygonVertOffset = 0,
|
|
6376
6422
|
rectIdx = 0,
|
|
6377
6423
|
ellipseIdx = 0,
|
|
6378
6424
|
curPipelineIndex = -1;
|
|
@@ -6400,12 +6446,18 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
|
|
|
6400
6446
|
} else if (curPipelineIndex == 6) {
|
|
6401
6447
|
pass.setIndexBuffer(ellipseIndexBuffer, 'uint16');
|
|
6402
6448
|
pass.setBindGroup(1, ellipseBindGroup);
|
|
6449
|
+
} else if (curPipelineIndex == 7) {
|
|
6450
|
+
pass.setBindGroup(1, polyPtsBindGroup);
|
|
6403
6451
|
} else if ($._customBindHandlers[curPipelineIndex]) {
|
|
6404
6452
|
$._customBindHandlers[curPipelineIndex](pass);
|
|
6405
6453
|
}
|
|
6406
6454
|
}
|
|
6407
6455
|
|
|
6408
|
-
if (curPipelineIndex ==
|
|
6456
|
+
if (curPipelineIndex == 7) {
|
|
6457
|
+
// draw a polygon
|
|
6458
|
+
pass.draw(v, 1, polygonVertOffset, 0);
|
|
6459
|
+
polygonVertOffset += v;
|
|
6460
|
+
} else if (curPipelineIndex == 6) {
|
|
6409
6461
|
// draw an ellipse
|
|
6410
6462
|
pass.drawIndexed(18, v, 0, 0, ellipseIdx);
|
|
6411
6463
|
ellipseIdx += v;
|
|
@@ -6482,6 +6534,8 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
|
|
|
6482
6534
|
|
|
6483
6535
|
// reset
|
|
6484
6536
|
shapesVertIdx = 0;
|
|
6537
|
+
polygonVertIdx = 0;
|
|
6538
|
+
polyPtsIdx = 0;
|
|
6485
6539
|
imgVertIdx = 0;
|
|
6486
6540
|
// Remove video frames without creating new array
|
|
6487
6541
|
if (vidFrames > 0) {
|
|
@@ -6632,19 +6686,16 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
|
|
|
6632
6686
|
};
|
|
6633
6687
|
|
|
6634
6688
|
$.vertex = (x, y) => {
|
|
6635
|
-
|
|
6636
|
-
sv.push(x, y, fillIdx, matrixIdx);
|
|
6689
|
+
sv.push(x, y, fillIdx);
|
|
6637
6690
|
shapeVertCount++;
|
|
6638
6691
|
};
|
|
6639
6692
|
|
|
6640
6693
|
$.curveVertex = (x, y) => {
|
|
6641
|
-
if (matrixDirty) saveMatrix();
|
|
6642
6694
|
curveVertices.push({ x, y });
|
|
6643
6695
|
};
|
|
6644
6696
|
|
|
6645
6697
|
$.bezierVertex = function (cx1, cy1, cx2, cy2, x, y) {
|
|
6646
6698
|
if (shapeVertCount === 0) throw new Error('Shape needs a vertex()');
|
|
6647
|
-
if (matrixDirty) saveMatrix();
|
|
6648
6699
|
|
|
6649
6700
|
// Get the last vertex as the starting point (P₀)
|
|
6650
6701
|
let prevIndex = (shapeVertCount - 1) * 4;
|
|
@@ -6680,136 +6731,413 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
|
|
|
6680
6731
|
vy = mt3 * startY + 3 * mt2 * t * cy1 + 3 * mt * t2 * cy2 + t3 * y;
|
|
6681
6732
|
}
|
|
6682
6733
|
|
|
6683
|
-
sv.push(vx, vy, fillIdx
|
|
6734
|
+
sv.push(vx, vy, fillIdx);
|
|
6684
6735
|
shapeVertCount++;
|
|
6685
6736
|
}
|
|
6686
6737
|
};
|
|
6687
6738
|
|
|
6688
6739
|
$.quadraticVertex = (cx, cy, x, y) => $.bezierVertex(cx, cy, x, y);
|
|
6689
6740
|
|
|
6741
|
+
function addQuad(x1, y1, x2, y2, x3, y3, x4, y4, ci, ti) {
|
|
6742
|
+
addVert(x1, y1, ci, ti); // v0
|
|
6743
|
+
addVert(x2, y2, ci, ti); // v1
|
|
6744
|
+
addVert(x4, y4, ci, ti); // v3
|
|
6745
|
+
addVert(x3, y3, ci, ti); // v2
|
|
6746
|
+
drawStack.push(shapesPL, 4);
|
|
6747
|
+
}
|
|
6748
|
+
|
|
6749
|
+
$.plane = (x, y, w, h) => {
|
|
6750
|
+
h ??= w;
|
|
6751
|
+
let [l, r, t, b] = calcBox(x, y, w, h, 'center');
|
|
6752
|
+
if (matrixDirty) saveMatrix();
|
|
6753
|
+
addQuad(l, t, r, t, r, b, l, b, fillIdx, matrixIdx);
|
|
6754
|
+
};
|
|
6755
|
+
|
|
6756
|
+
$.curve = (x1, y1, x2, y2, x3, y3, x4, y4) => {
|
|
6757
|
+
$.beginShape();
|
|
6758
|
+
$.curveVertex(x1, y1);
|
|
6759
|
+
$.curveVertex(x2, y2);
|
|
6760
|
+
$.curveVertex(x3, y3);
|
|
6761
|
+
$.curveVertex(x4, y4);
|
|
6762
|
+
$.endShape();
|
|
6763
|
+
};
|
|
6764
|
+
|
|
6765
|
+
$.bezier = (x1, y1, x2, y2, x3, y3, x4, y4) => {
|
|
6766
|
+
$.beginShape();
|
|
6767
|
+
$.vertex(x1, y1);
|
|
6768
|
+
$.bezierVertex(x2, y2, x3, y3, x4, y4);
|
|
6769
|
+
$.endShape();
|
|
6770
|
+
};
|
|
6771
|
+
|
|
6772
|
+
/* POLYGONS */
|
|
6773
|
+
|
|
6774
|
+
let polygonPL = 7;
|
|
6775
|
+
|
|
6776
|
+
$._polygonShaderCode =
|
|
6777
|
+
$._baseShaderCode +
|
|
6778
|
+
/* wgsl */ `
|
|
6779
|
+
struct VertexParams {
|
|
6780
|
+
@builtin(vertex_index) vertexIndex : u32,
|
|
6781
|
+
@location(0) pos: vec2f,
|
|
6782
|
+
@location(1) polyStart: f32,
|
|
6783
|
+
@location(2) polyCount: f32,
|
|
6784
|
+
@location(3) fillIndex: f32,
|
|
6785
|
+
@location(4) strokeIndex: f32,
|
|
6786
|
+
@location(5) strokeWeight: f32,
|
|
6787
|
+
@location(6) matrixIndex: f32
|
|
6788
|
+
}
|
|
6789
|
+
|
|
6790
|
+
struct FragParams {
|
|
6791
|
+
@builtin(position) position: vec4f,
|
|
6792
|
+
@location(0) localPos: vec2f,
|
|
6793
|
+
@location(1) @interpolate(flat) polyStart: u32,
|
|
6794
|
+
@location(2) @interpolate(flat) polyCount: u32,
|
|
6795
|
+
@location(3) @interpolate(flat) fillIndex: f32,
|
|
6796
|
+
@location(4) @interpolate(flat) strokeIndex: f32,
|
|
6797
|
+
@location(5) @interpolate(flat) strokeWeight: f32,
|
|
6798
|
+
@location(6) @interpolate(flat) isClosed: f32
|
|
6799
|
+
}
|
|
6800
|
+
|
|
6801
|
+
@group(0) @binding(0) var<uniform> q: Q5;
|
|
6802
|
+
@group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;
|
|
6803
|
+
@group(0) @binding(2) var<storage> colors : array<vec4f>;
|
|
6804
|
+
|
|
6805
|
+
@group(1) @binding(0) var<storage, read> polyPts: array<vec4f>;
|
|
6806
|
+
|
|
6807
|
+
fn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {
|
|
6808
|
+
var vert = vec4f(pos, 0.0, 1.0);
|
|
6809
|
+
vert = transforms[i32(matrixIndex)] * vert;
|
|
6810
|
+
vert.x /= q.halfWidth;
|
|
6811
|
+
vert.y /= q.halfHeight;
|
|
6812
|
+
return vert;
|
|
6813
|
+
}
|
|
6814
|
+
|
|
6815
|
+
fn getPolyColor(p: vec2f, start: u32, count: u32, fIdx: f32) -> vec4f {
|
|
6816
|
+
let uniformColor = colors[i32(fIdx)];
|
|
6817
|
+
if (uniformColor.a == 0.0) {
|
|
6818
|
+
return uniformColor;
|
|
6819
|
+
}
|
|
6820
|
+
|
|
6821
|
+
var sumWeight: f32 = 0.0;
|
|
6822
|
+
var sumColor = vec4f(0.0);
|
|
6823
|
+
for (var i: u32 = 0u; i < count; i = i + 1u) {
|
|
6824
|
+
let pt = polyPts[start + i];
|
|
6825
|
+
let d = distance(p, pt.xy);
|
|
6826
|
+
if (d < 0.1) {
|
|
6827
|
+
return colors[i32(pt.z)];
|
|
6828
|
+
}
|
|
6829
|
+
let w = 1.0 / (d * d * d);
|
|
6830
|
+
sumWeight += w;
|
|
6831
|
+
sumColor += colors[i32(pt.z)] * w;
|
|
6832
|
+
}
|
|
6833
|
+
return sumColor / sumWeight;
|
|
6834
|
+
}
|
|
6835
|
+
|
|
6836
|
+
fn sdPolygon(p: vec2f, start: u32, count: u32, isClosed: f32) -> f32 {
|
|
6837
|
+
var d: f32 = dot(p - polyPts[start].xy, p - polyPts[start].xy);
|
|
6838
|
+
var s: f32 = 1.0;
|
|
6839
|
+
var j: u32 = count - 1u;
|
|
6840
|
+
for (var i: u32 = 0u; i < count; i = i + 1u) {
|
|
6841
|
+
let vi = polyPts[start + i].xy;
|
|
6842
|
+
let vj = polyPts[start + j].xy;
|
|
6843
|
+
let e = vj - vi;
|
|
6844
|
+
let w = p - vi;
|
|
6845
|
+
let b = w - e * clamp(dot(w, e) / dot(e, e), 0.0, 1.0);
|
|
6846
|
+
let bSq = dot(b, b);
|
|
6847
|
+
if (isClosed != 0.0 || i != 0u) {
|
|
6848
|
+
if (bSq < d) { d = bSq; }
|
|
6849
|
+
}
|
|
6850
|
+
|
|
6851
|
+
let condX = p.y >= vi.y;
|
|
6852
|
+
let condY = p.y < vj.y;
|
|
6853
|
+
let condZ = e.x * w.y > e.y * w.x;
|
|
6854
|
+
if ((condX && condY && condZ) || (!condX && !condY && !condZ)) {
|
|
6855
|
+
s = -s;
|
|
6856
|
+
}
|
|
6857
|
+
j = i;
|
|
6858
|
+
}
|
|
6859
|
+
if (isClosed == 0.0) {
|
|
6860
|
+
return sqrt(d);
|
|
6861
|
+
}
|
|
6862
|
+
return s * sqrt(d);
|
|
6863
|
+
}
|
|
6864
|
+
|
|
6865
|
+
@vertex
|
|
6866
|
+
fn vertexMain(v: VertexParams) -> FragParams {
|
|
6867
|
+
var f: FragParams;
|
|
6868
|
+
|
|
6869
|
+
// manually apply transform
|
|
6870
|
+
var vert = vec4f(v.pos, 0.0, 1.0);
|
|
6871
|
+
vert = transforms[i32(v.matrixIndex)] * vert;
|
|
6872
|
+
vert.x /= q.halfWidth;
|
|
6873
|
+
vert.y /= q.halfHeight;
|
|
6874
|
+
|
|
6875
|
+
f.position = vert;
|
|
6876
|
+
f.localPos = v.pos;
|
|
6877
|
+
f.polyStart = u32(v.polyStart + 0.1);
|
|
6878
|
+
f.polyCount = u32(abs(v.polyCount) + 0.1);
|
|
6879
|
+
f.isClosed = step(0.0, v.polyCount);
|
|
6880
|
+
f.fillIndex = v.fillIndex;
|
|
6881
|
+
f.strokeIndex = v.strokeIndex;
|
|
6882
|
+
f.strokeWeight = v.strokeWeight;
|
|
6883
|
+
return f;
|
|
6884
|
+
}
|
|
6885
|
+
|
|
6886
|
+
@fragment
|
|
6887
|
+
fn fragMain(f: FragParams) -> @location(0) vec4f {
|
|
6888
|
+
let dist = sdPolygon(f.localPos, f.polyStart, f.polyCount, f.isClosed);
|
|
6889
|
+
let fill = getPolyColor(f.localPos, f.polyStart, f.polyCount, f.fillIndex);
|
|
6890
|
+
let stroke = colors[i32(f.strokeIndex)];
|
|
6891
|
+
|
|
6892
|
+
let dpdx_d = dpdx(dist);
|
|
6893
|
+
let dpdy_d = dpdy(dist);
|
|
6894
|
+
let distGrad = sqrt(dpdx_d * dpdx_d + dpdy_d * dpdy_d);
|
|
6895
|
+
let aa = clamp(distGrad * 1.5, 0.001, 2.0);
|
|
6896
|
+
|
|
6897
|
+
let halfStroke = f.strokeWeight * 0.5;
|
|
6898
|
+
|
|
6899
|
+
var outFragColor: vec4f;
|
|
6900
|
+
|
|
6901
|
+
if (fill.a != 0.0 && f.strokeWeight == 0.0) {
|
|
6902
|
+
let fillAlpha = 1.0 - smoothstep(-aa, aa, dist);
|
|
6903
|
+
if (fillAlpha <= 0.0) { discard; }
|
|
6904
|
+
outFragColor = vec4f(fill.rgb, fill.a * fillAlpha);
|
|
6905
|
+
} else if (fill.a != 0.0) {
|
|
6906
|
+
let fillAlpha = 1.0 - smoothstep(-aa, aa, dist);
|
|
6907
|
+
let strokeDist = abs(dist) - halfStroke;
|
|
6908
|
+
let strokeAlphaMask = 1.0 - smoothstep(-aa, aa, strokeDist);
|
|
6909
|
+
|
|
6910
|
+
if (fillAlpha <= 0.0 && strokeAlphaMask <= 0.0) { discard; }
|
|
6911
|
+
|
|
6912
|
+
let sA = stroke.a * strokeAlphaMask;
|
|
6913
|
+
let fA = fill.a * fillAlpha;
|
|
6914
|
+
let outAlpha = sA + fA * (1.0 - sA);
|
|
6915
|
+
let outCol = stroke.rgb * sA + fill.rgb * fA * (1.0 - sA);
|
|
6916
|
+
outFragColor = vec4f(outCol / max(outAlpha, 1e-5), outAlpha);
|
|
6917
|
+
} else {
|
|
6918
|
+
let strokeDist = abs(dist) - halfStroke;
|
|
6919
|
+
let strokeAlpha = 1.0 - smoothstep(-aa, aa, strokeDist);
|
|
6920
|
+
|
|
6921
|
+
if (strokeAlpha <= 0.0) { discard; }
|
|
6922
|
+
outFragColor = vec4f(stroke.rgb, stroke.a * strokeAlpha);
|
|
6923
|
+
}
|
|
6924
|
+
return outFragColor;
|
|
6925
|
+
}
|
|
6926
|
+
`;
|
|
6927
|
+
|
|
6928
|
+
let polygonShader = Q5.device.createShaderModule({
|
|
6929
|
+
label: 'polygonShader',
|
|
6930
|
+
code: $._polygonShaderCode
|
|
6931
|
+
});
|
|
6932
|
+
|
|
6933
|
+
let polygonVertStack = new Float32Array($._isGraphics ? 1000 : 1e7),
|
|
6934
|
+
polygonVertIdx = 0;
|
|
6935
|
+
let polyPtsStack = new Float32Array($._isGraphics ? 1000 : 1e7),
|
|
6936
|
+
polyPtsIdx = 0;
|
|
6937
|
+
|
|
6938
|
+
let polygonVertBuffLayout = {
|
|
6939
|
+
arrayStride: 32, // 8 floats * 4 bytes
|
|
6940
|
+
attributes: [
|
|
6941
|
+
{ format: 'float32x2', offset: 0, shaderLocation: 0 },
|
|
6942
|
+
{ format: 'float32', offset: 8, shaderLocation: 1 },
|
|
6943
|
+
{ format: 'float32', offset: 12, shaderLocation: 2 },
|
|
6944
|
+
{ format: 'float32', offset: 16, shaderLocation: 3 },
|
|
6945
|
+
{ format: 'float32', offset: 20, shaderLocation: 4 },
|
|
6946
|
+
{ format: 'float32', offset: 24, shaderLocation: 5 },
|
|
6947
|
+
{ format: 'float32', offset: 28, shaderLocation: 6 }
|
|
6948
|
+
]
|
|
6949
|
+
};
|
|
6950
|
+
|
|
6951
|
+
let polygonBindGroupLayout = Q5.device.createBindGroupLayout({
|
|
6952
|
+
entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'read-only-storage' } }]
|
|
6953
|
+
});
|
|
6954
|
+
|
|
6955
|
+
let polygonPipelineLayout = Q5.device.createPipelineLayout({
|
|
6956
|
+
label: 'polygonPipelineLayout',
|
|
6957
|
+
bindGroupLayouts: [mainLayout, polygonBindGroupLayout]
|
|
6958
|
+
});
|
|
6959
|
+
|
|
6960
|
+
$._pipelineConfigs[7] = {
|
|
6961
|
+
label: 'polygonPipeline',
|
|
6962
|
+
layout: polygonPipelineLayout,
|
|
6963
|
+
vertex: { module: polygonShader, entryPoint: 'vertexMain', buffers: [null, null, polygonVertBuffLayout] },
|
|
6964
|
+
fragment: {
|
|
6965
|
+
module: polygonShader,
|
|
6966
|
+
entryPoint: 'fragMain',
|
|
6967
|
+
targets: [{ format: 'bgra8unorm', blend: $.blendConfigs['source-over'] }]
|
|
6968
|
+
},
|
|
6969
|
+
primitive: { topology: 'triangle-list' },
|
|
6970
|
+
multisample: { count: 4 }
|
|
6971
|
+
};
|
|
6972
|
+
$._pipelines[7] = Q5.device.createRenderPipeline($._pipelineConfigs[7]);
|
|
6973
|
+
|
|
6974
|
+
const addPolygonVert = (x, y, start, count, fIdx, sIdx, sWeight, mIdx) => {
|
|
6975
|
+
let v = polygonVertStack,
|
|
6976
|
+
i = polygonVertIdx;
|
|
6977
|
+
v[i++] = x;
|
|
6978
|
+
v[i++] = y;
|
|
6979
|
+
v[i++] = start;
|
|
6980
|
+
v[i++] = count;
|
|
6981
|
+
v[i++] = fIdx;
|
|
6982
|
+
v[i++] = sIdx;
|
|
6983
|
+
v[i++] = sWeight;
|
|
6984
|
+
v[i++] = mIdx;
|
|
6985
|
+
polygonVertIdx = i;
|
|
6986
|
+
};
|
|
6987
|
+
|
|
6690
6988
|
$.endShape = (close) => {
|
|
6691
6989
|
if (curveVertices.length > 0) {
|
|
6692
|
-
// duplicate start and end points if necessary
|
|
6693
6990
|
let points = [...curveVertices];
|
|
6694
6991
|
if (points.length < 4) {
|
|
6695
|
-
// duplicate first and last points
|
|
6696
6992
|
while (points.length < 4) {
|
|
6697
6993
|
points.unshift(points[0]);
|
|
6698
6994
|
points.push(points[points.length - 1]);
|
|
6699
6995
|
}
|
|
6700
6996
|
}
|
|
6701
|
-
|
|
6702
|
-
// Use curveSegments to determine step size
|
|
6703
6997
|
let step = 1 / curveSegments;
|
|
6704
|
-
|
|
6705
|
-
// calculate catmull-rom spline curve points
|
|
6706
6998
|
for (let i = 0; i < points.length - 3; i++) {
|
|
6707
|
-
let p0 = points[i]
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
for (let
|
|
6713
|
-
let
|
|
6714
|
-
let
|
|
6715
|
-
|
|
6999
|
+
let p0 = points[i],
|
|
7000
|
+
p1 = points[i + 1],
|
|
7001
|
+
p2 = points[i + 2],
|
|
7002
|
+
p3 = points[i + 3];
|
|
7003
|
+
let startT = i === 0 ? 0 : 1;
|
|
7004
|
+
for (let j = startT; j <= curveSegments; j++) {
|
|
7005
|
+
let t = j / curveSegments;
|
|
7006
|
+
let t2 = t * t,
|
|
7007
|
+
t3 = t2 * t;
|
|
6716
7008
|
let x =
|
|
6717
7009
|
0.5 *
|
|
6718
7010
|
(2 * p1.x +
|
|
6719
7011
|
(-p0.x + p2.x) * t +
|
|
6720
7012
|
(2 * p0.x - 5 * p1.x + 4 * p2.x - p3.x) * t2 +
|
|
6721
7013
|
(-p0.x + 3 * p1.x - 3 * p2.x + p3.x) * t3);
|
|
6722
|
-
|
|
6723
7014
|
let y =
|
|
6724
7015
|
0.5 *
|
|
6725
7016
|
(2 * p1.y +
|
|
6726
7017
|
(-p0.y + p2.y) * t +
|
|
6727
7018
|
(2 * p0.y - 5 * p1.y + 4 * p2.y - p3.y) * t2 +
|
|
6728
7019
|
(-p0.y + 3 * p1.y - 3 * p2.y + p3.y) * t3);
|
|
6729
|
-
|
|
6730
|
-
sv.push(x, y, fillIdx, matrixIdx);
|
|
7020
|
+
sv.push(x, y, fillIdx);
|
|
6731
7021
|
shapeVertCount++;
|
|
6732
7022
|
}
|
|
6733
7023
|
}
|
|
6734
7024
|
}
|
|
6735
7025
|
|
|
6736
7026
|
if (!shapeVertCount) return;
|
|
6737
|
-
if (shapeVertCount == 1)
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
if (firstX !== lastX || firstY !== lastY) {
|
|
6751
|
-
sv.push(firstX, firstY, sv[firstIndex + 2], sv[firstIndex + 3]);
|
|
6752
|
-
shapeVertCount++;
|
|
6753
|
-
}
|
|
7027
|
+
if (shapeVertCount == 1) {
|
|
7028
|
+
$.point(sv[0], sv[1]);
|
|
7029
|
+
shapeVertCount = 0;
|
|
7030
|
+
sv = [];
|
|
7031
|
+
curveVertices = [];
|
|
7032
|
+
return;
|
|
7033
|
+
}
|
|
7034
|
+
if (shapeVertCount == 2) {
|
|
7035
|
+
$.line(sv[0], sv[1], sv[3], sv[4]);
|
|
7036
|
+
shapeVertCount = 0;
|
|
7037
|
+
sv = [];
|
|
7038
|
+
curveVertices = [];
|
|
7039
|
+
return;
|
|
6754
7040
|
}
|
|
6755
7041
|
|
|
6756
|
-
if (
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
addVert(sv[v2], sv[v2 + 1], sv[v2 + 2], sv[v2 + 3]);
|
|
6774
|
-
}
|
|
6775
|
-
drawStack.push(shapesPL, (shapeVertCount - 2) * 3);
|
|
6776
|
-
}
|
|
7042
|
+
if (matrixDirty) saveMatrix();
|
|
7043
|
+
let ti = matrixIdx;
|
|
7044
|
+
|
|
7045
|
+
let isAutoClosed = false;
|
|
7046
|
+
let isClosedPath = false;
|
|
7047
|
+
let firstX = sv[0],
|
|
7048
|
+
firstY = sv[1];
|
|
7049
|
+
let lastX = sv[(shapeVertCount - 1) * 3],
|
|
7050
|
+
lastY = sv[(shapeVertCount - 1) * 3 + 1];
|
|
7051
|
+
|
|
7052
|
+
if (firstX === lastX && firstY === lastY) {
|
|
7053
|
+
isClosedPath = true;
|
|
7054
|
+
} else if (close || doFill) {
|
|
7055
|
+
sv.push(firstX, firstY, sv[2]);
|
|
7056
|
+
shapeVertCount++;
|
|
7057
|
+
isAutoClosed = !close;
|
|
7058
|
+
isClosedPath = true;
|
|
6777
7059
|
}
|
|
6778
7060
|
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
7061
|
+
let runSDF = shapeVertCount >= 3 && doStroke;
|
|
7062
|
+
|
|
7063
|
+
if (runSDF) {
|
|
7064
|
+
let fi = doFill ? fillIdx : 0,
|
|
7065
|
+
si = strokeIdx;
|
|
7066
|
+
|
|
7067
|
+
let polyStart = polyPtsIdx / 4,
|
|
7068
|
+
polyCount = isClosedPath ? shapeVertCount - 1 : shapeVertCount;
|
|
7069
|
+
for (let i = 0; i < polyCount; i++) {
|
|
7070
|
+
polyPtsStack[polyPtsIdx++] = sv[i * 3];
|
|
7071
|
+
polyPtsStack[polyPtsIdx++] = sv[i * 3 + 1];
|
|
7072
|
+
polyPtsStack[polyPtsIdx++] = sv[i * 3 + 2];
|
|
7073
|
+
polyPtsStack[polyPtsIdx++] = ti;
|
|
7074
|
+
}
|
|
7075
|
+
|
|
7076
|
+
let minX = Infinity,
|
|
7077
|
+
minY = Infinity,
|
|
7078
|
+
maxX = -Infinity,
|
|
7079
|
+
maxY = -Infinity;
|
|
7080
|
+
for (let i = 0; i < shapeVertCount; i++) {
|
|
7081
|
+
let vx = sv[i * 3],
|
|
7082
|
+
vy = sv[i * 3 + 1];
|
|
7083
|
+
if (vx < minX) minX = vx;
|
|
7084
|
+
if (vx > maxX) maxX = vx;
|
|
7085
|
+
if (vy < minY) minY = vy;
|
|
7086
|
+
if (vy > maxY) maxY = vy;
|
|
7087
|
+
}
|
|
7088
|
+
let padding = sw * 0.5 + 1.0; // padding for stroke and AA
|
|
7089
|
+
minX -= padding;
|
|
7090
|
+
minY -= padding;
|
|
7091
|
+
maxX += padding;
|
|
7092
|
+
maxY += padding;
|
|
7093
|
+
|
|
7094
|
+
let passedCount = isClosedPath ? polyCount : -polyCount;
|
|
7095
|
+
addPolygonVert(minX, minY, polyStart, passedCount, fi, si, sw, ti);
|
|
7096
|
+
addPolygonVert(maxX, minY, polyStart, passedCount, fi, si, sw, ti);
|
|
7097
|
+
addPolygonVert(minX, maxY, polyStart, passedCount, fi, si, sw, ti);
|
|
7098
|
+
|
|
7099
|
+
addPolygonVert(maxX, minY, polyStart, passedCount, fi, si, sw, ti);
|
|
7100
|
+
addPolygonVert(maxX, maxY, polyStart, passedCount, fi, si, sw, ti);
|
|
7101
|
+
addPolygonVert(minX, maxY, polyStart, passedCount, fi, si, sw, ti);
|
|
7102
|
+
|
|
7103
|
+
drawStack.push(polygonPL, 6);
|
|
7104
|
+
} else {
|
|
7105
|
+
if (doFill) {
|
|
7106
|
+
if (shapeVertCount == 5) {
|
|
7107
|
+
// Quads
|
|
7108
|
+
addVert(sv[0], sv[1], sv[2], ti);
|
|
7109
|
+
addVert(sv[3], sv[4], sv[5], ti);
|
|
7110
|
+
addVert(sv[9], sv[10], sv[11], ti);
|
|
7111
|
+
addVert(sv[6], sv[7], sv[8], ti);
|
|
7112
|
+
drawStack.push(shapesPL, 4);
|
|
7113
|
+
} else {
|
|
7114
|
+
// Triangulation fan
|
|
7115
|
+
for (let i = 1; i < shapeVertCount - 1; i++) {
|
|
7116
|
+
let v0 = 0,
|
|
7117
|
+
v1 = i * 3,
|
|
7118
|
+
v2 = (i + 1) * 3;
|
|
7119
|
+
addVert(sv[v0], sv[v0 + 1], sv[v0 + 2], ti);
|
|
7120
|
+
addVert(sv[v1], sv[v1 + 1], sv[v1 + 2], ti);
|
|
7121
|
+
addVert(sv[v2], sv[v2 + 1], sv[v2 + 2], ti);
|
|
7122
|
+
}
|
|
7123
|
+
drawStack.push(shapesPL, (shapeVertCount - 2) * 3);
|
|
7124
|
+
}
|
|
7125
|
+
}
|
|
7126
|
+
if (doStroke) {
|
|
7127
|
+
let maxLines = isAutoClosed ? shapeVertCount - 2 : shapeVertCount - 1;
|
|
7128
|
+
for (let i = 0; i < maxLines; i++) {
|
|
7129
|
+
let v1 = i * 3,
|
|
7130
|
+
v2 = (i + 1) * 3;
|
|
7131
|
+
$.line(sv[v1], sv[v1 + 1], sv[v2], sv[v2 + 1]);
|
|
7132
|
+
}
|
|
6785
7133
|
}
|
|
6786
|
-
let v1 = (shapeVertCount - 1) * 4;
|
|
6787
|
-
let v2 = 0;
|
|
6788
|
-
if (close) $.line(sv[v1], sv[v1 + 1], sv[v2], sv[v2 + 1]);
|
|
6789
7134
|
}
|
|
6790
7135
|
|
|
6791
|
-
// reset for the next shape
|
|
6792
7136
|
shapeVertCount = 0;
|
|
6793
7137
|
sv = [];
|
|
6794
7138
|
curveVertices = [];
|
|
6795
7139
|
};
|
|
6796
7140
|
|
|
6797
|
-
$.curve = (x1, y1, x2, y2, x3, y3, x4, y4) => {
|
|
6798
|
-
$.beginShape();
|
|
6799
|
-
$.curveVertex(x1, y1);
|
|
6800
|
-
$.curveVertex(x2, y2);
|
|
6801
|
-
$.curveVertex(x3, y3);
|
|
6802
|
-
$.curveVertex(x4, y4);
|
|
6803
|
-
$.endShape();
|
|
6804
|
-
};
|
|
6805
|
-
|
|
6806
|
-
$.bezier = (x1, y1, x2, y2, x3, y3, x4, y4) => {
|
|
6807
|
-
$.beginShape();
|
|
6808
|
-
$.vertex(x1, y1);
|
|
6809
|
-
$.bezierVertex(x2, y2, x3, y3, x4, y4);
|
|
6810
|
-
$.endShape();
|
|
6811
|
-
};
|
|
6812
|
-
|
|
6813
7141
|
$.triangle = (x1, y1, x2, y2, x3, y3) => {
|
|
6814
7142
|
$.beginShape();
|
|
6815
7143
|
$.vertex(x1, y1);
|
|
@@ -6827,21 +7155,6 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
|
|
|
6827
7155
|
$.endShape(true);
|
|
6828
7156
|
};
|
|
6829
7157
|
|
|
6830
|
-
function addQuad(x1, y1, x2, y2, x3, y3, x4, y4, ci, ti) {
|
|
6831
|
-
addVert(x1, y1, ci, ti); // v0
|
|
6832
|
-
addVert(x2, y2, ci, ti); // v1
|
|
6833
|
-
addVert(x4, y4, ci, ti); // v3
|
|
6834
|
-
addVert(x3, y3, ci, ti); // v2
|
|
6835
|
-
drawStack.push(shapesPL, 4);
|
|
6836
|
-
}
|
|
6837
|
-
|
|
6838
|
-
$.plane = (x, y, w, h) => {
|
|
6839
|
-
h ??= w;
|
|
6840
|
-
let [l, r, t, b] = calcBox(x, y, w, h, 'center');
|
|
6841
|
-
if (matrixDirty) saveMatrix();
|
|
6842
|
-
addQuad(l, t, r, t, r, b, l, b, fillIdx, matrixIdx);
|
|
6843
|
-
};
|
|
6844
|
-
|
|
6845
7158
|
/* RECT */
|
|
6846
7159
|
|
|
6847
7160
|
let rectPL = 5;
|
|
@@ -7134,7 +7447,21 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
|
|
|
7134
7447
|
};
|
|
7135
7448
|
|
|
7136
7449
|
$.line = (x1, y1, x2, y2) => {
|
|
7137
|
-
if (doStroke)
|
|
7450
|
+
if (!doStroke) return;
|
|
7451
|
+
if (matrixDirty) saveMatrix();
|
|
7452
|
+
|
|
7453
|
+
let dx = x2 - x1,
|
|
7454
|
+
dy = y2 - y1,
|
|
7455
|
+
sqLen = dx * dx + dy * dy;
|
|
7456
|
+
|
|
7457
|
+
if (sqLen === 0) return;
|
|
7458
|
+
|
|
7459
|
+
let len = Math.sqrt(sqLen),
|
|
7460
|
+
ratio = hsw / len,
|
|
7461
|
+
nx = -dy * ratio,
|
|
7462
|
+
ny = dx * ratio;
|
|
7463
|
+
|
|
7464
|
+
addQuad(x1 + nx, y1 + ny, x1 - nx, y1 - ny, x2 - nx, y2 - ny, x2 + nx, y2 + ny, strokeIdx, matrixIdx);
|
|
7138
7465
|
};
|
|
7139
7466
|
|
|
7140
7467
|
/* ELLIPSE */
|
|
@@ -8777,6 +9104,8 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
|
|
|
8777
9104
|
transformsBuffer?.destroy();
|
|
8778
9105
|
colorsBuffer?.destroy();
|
|
8779
9106
|
shapesVertBuff?.destroy();
|
|
9107
|
+
polygonVertBuff?.destroy();
|
|
9108
|
+
polyPtsBuffer?.destroy();
|
|
8780
9109
|
imgVertBuff?.destroy();
|
|
8781
9110
|
charBuffer?.destroy();
|
|
8782
9111
|
textBuffer?.destroy();
|
|
@@ -8856,6 +9185,12 @@ Q5.initWebGPU = async () => {
|
|
|
8856
9185
|
|
|
8857
9186
|
Q5.device = device;
|
|
8858
9187
|
|
|
9188
|
+
if (typeof window == 'object') {
|
|
9189
|
+
window.addEventListener('pagehide', () => {
|
|
9190
|
+
if (device) device.destroy();
|
|
9191
|
+
});
|
|
9192
|
+
}
|
|
9193
|
+
|
|
8859
9194
|
return true;
|
|
8860
9195
|
};
|
|
8861
9196
|
|