q5 4.3.0 → 4.4.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/deno.json +1 -1
- package/package.json +1 -1
- package/q5.d.ts +51 -21
- package/q5.js +455 -110
- 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
|
|
@@ -490,7 +490,7 @@ if (typeof window == 'object') {
|
|
|
490
490
|
window.addEventListener('pagehide', cleanup);
|
|
491
491
|
} else global.window = 0;
|
|
492
492
|
|
|
493
|
-
Q5.version = Q5.VERSION = '4.
|
|
493
|
+
Q5.version = Q5.VERSION = '4.4';
|
|
494
494
|
|
|
495
495
|
if (typeof document == 'object') {
|
|
496
496
|
document.addEventListener('DOMContentLoaded', () => {
|
|
@@ -6153,11 +6153,16 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
|
|
|
6153
6153
|
$.pop();
|
|
6154
6154
|
} else {
|
|
6155
6155
|
addColor(r, g, b, a);
|
|
6156
|
-
let
|
|
6156
|
+
let ci = colorIndex,
|
|
6157
|
+
lx = -c.hw,
|
|
6157
6158
|
rx = c.hw,
|
|
6158
6159
|
ty = -c.hh,
|
|
6159
6160
|
by = c.hh;
|
|
6160
|
-
|
|
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
|
|
6161
6166
|
}
|
|
6162
6167
|
};
|
|
6163
6168
|
|
|
@@ -6197,7 +6202,15 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
|
|
|
6197
6202
|
shouldClear = false;
|
|
6198
6203
|
};
|
|
6199
6204
|
|
|
6200
|
-
let transformsBuffer,
|
|
6205
|
+
let transformsBuffer,
|
|
6206
|
+
colorsBuffer,
|
|
6207
|
+
shapesVertBuff,
|
|
6208
|
+
imgVertBuff,
|
|
6209
|
+
polygonVertBuff,
|
|
6210
|
+
polyPtsBuffer,
|
|
6211
|
+
polyPtsBindGroup,
|
|
6212
|
+
charBuffer,
|
|
6213
|
+
textBuffer;
|
|
6201
6214
|
let mainBindGroup, lastTransformsBuffer, lastColorsBuffer;
|
|
6202
6215
|
|
|
6203
6216
|
$._render = () => {
|
|
@@ -6276,6 +6289,37 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
|
|
|
6276
6289
|
|
|
6277
6290
|
// prepare to render images and videos
|
|
6278
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
|
+
|
|
6279
6323
|
if (imgVertIdx) {
|
|
6280
6324
|
$._pass.setPipeline($._pipelines[2]); // images pipeline
|
|
6281
6325
|
|
|
@@ -6374,6 +6418,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
|
|
|
6374
6418
|
let drawVertOffset = 0,
|
|
6375
6419
|
imageVertOffset = 0,
|
|
6376
6420
|
textCharOffset = 0,
|
|
6421
|
+
polygonVertOffset = 0,
|
|
6377
6422
|
rectIdx = 0,
|
|
6378
6423
|
ellipseIdx = 0,
|
|
6379
6424
|
curPipelineIndex = -1;
|
|
@@ -6401,12 +6446,18 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
|
|
|
6401
6446
|
} else if (curPipelineIndex == 6) {
|
|
6402
6447
|
pass.setIndexBuffer(ellipseIndexBuffer, 'uint16');
|
|
6403
6448
|
pass.setBindGroup(1, ellipseBindGroup);
|
|
6449
|
+
} else if (curPipelineIndex == 7) {
|
|
6450
|
+
pass.setBindGroup(1, polyPtsBindGroup);
|
|
6404
6451
|
} else if ($._customBindHandlers[curPipelineIndex]) {
|
|
6405
6452
|
$._customBindHandlers[curPipelineIndex](pass);
|
|
6406
6453
|
}
|
|
6407
6454
|
}
|
|
6408
6455
|
|
|
6409
|
-
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) {
|
|
6410
6461
|
// draw an ellipse
|
|
6411
6462
|
pass.drawIndexed(18, v, 0, 0, ellipseIdx);
|
|
6412
6463
|
ellipseIdx += v;
|
|
@@ -6483,6 +6534,8 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
|
|
|
6483
6534
|
|
|
6484
6535
|
// reset
|
|
6485
6536
|
shapesVertIdx = 0;
|
|
6537
|
+
polygonVertIdx = 0;
|
|
6538
|
+
polyPtsIdx = 0;
|
|
6486
6539
|
imgVertIdx = 0;
|
|
6487
6540
|
// Remove video frames without creating new array
|
|
6488
6541
|
if (vidFrames > 0) {
|
|
@@ -6633,19 +6686,16 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
|
|
|
6633
6686
|
};
|
|
6634
6687
|
|
|
6635
6688
|
$.vertex = (x, y) => {
|
|
6636
|
-
|
|
6637
|
-
sv.push(x, y, fillIdx, matrixIdx);
|
|
6689
|
+
sv.push(x, y, fillIdx);
|
|
6638
6690
|
shapeVertCount++;
|
|
6639
6691
|
};
|
|
6640
6692
|
|
|
6641
6693
|
$.curveVertex = (x, y) => {
|
|
6642
|
-
if (matrixDirty) saveMatrix();
|
|
6643
6694
|
curveVertices.push({ x, y });
|
|
6644
6695
|
};
|
|
6645
6696
|
|
|
6646
6697
|
$.bezierVertex = function (cx1, cy1, cx2, cy2, x, y) {
|
|
6647
6698
|
if (shapeVertCount === 0) throw new Error('Shape needs a vertex()');
|
|
6648
|
-
if (matrixDirty) saveMatrix();
|
|
6649
6699
|
|
|
6650
6700
|
// Get the last vertex as the starting point (P₀)
|
|
6651
6701
|
let prevIndex = (shapeVertCount - 1) * 4;
|
|
@@ -6681,136 +6731,430 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
|
|
|
6681
6731
|
vy = mt3 * startY + 3 * mt2 * t * cy1 + 3 * mt * t2 * cy2 + t3 * y;
|
|
6682
6732
|
}
|
|
6683
6733
|
|
|
6684
|
-
sv.push(vx, vy, fillIdx
|
|
6734
|
+
sv.push(vx, vy, fillIdx);
|
|
6685
6735
|
shapeVertCount++;
|
|
6686
6736
|
}
|
|
6687
6737
|
};
|
|
6688
6738
|
|
|
6689
6739
|
$.quadraticVertex = (cx, cy, x, y) => $.bezierVertex(cx, cy, x, y);
|
|
6690
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 fill = getPolyColor(f.localPos, f.polyStart, f.polyCount, f.fillIndex);
|
|
6889
|
+
let stroke = colors[i32(f.strokeIndex)];
|
|
6890
|
+
|
|
6891
|
+
// f.isClosed is derived from the sign of v.polyCount (used for fill closure)
|
|
6892
|
+
let distFill = sdPolygon(f.localPos, f.polyStart, f.polyCount, f.isClosed);
|
|
6893
|
+
|
|
6894
|
+
// encode stroke-closure in the sign of strokeWeight; use absolute stroke weight for width
|
|
6895
|
+
let isClosedStroke = step(0.0, f.strokeWeight);
|
|
6896
|
+
let strokeW = abs(f.strokeWeight);
|
|
6897
|
+
let distStroke = sdPolygon(f.localPos, f.polyStart, f.polyCount, isClosedStroke);
|
|
6898
|
+
|
|
6899
|
+
// compute AA using gradients from both distances (conservative)
|
|
6900
|
+
let dpdx_fill = dpdx(distFill);
|
|
6901
|
+
let dpdy_fill = dpdy(distFill);
|
|
6902
|
+
let gradFill = sqrt(dpdx_fill * dpdx_fill + dpdy_fill * dpdy_fill);
|
|
6903
|
+
|
|
6904
|
+
let dpdx_stroke = dpdx(distStroke);
|
|
6905
|
+
let dpdy_stroke = dpdy(distStroke);
|
|
6906
|
+
let gradStroke = sqrt(dpdx_stroke * dpdx_stroke + dpdy_stroke * dpdy_stroke);
|
|
6907
|
+
|
|
6908
|
+
let aa = clamp(max(gradFill, gradStroke) * 1.5, 0.001, 2.0);
|
|
6909
|
+
|
|
6910
|
+
let halfStroke = strokeW * 0.5;
|
|
6911
|
+
|
|
6912
|
+
var outFragColor: vec4f;
|
|
6913
|
+
|
|
6914
|
+
if (fill.a != 0.0 && strokeW == 0.0) {
|
|
6915
|
+
let fillAlpha = 1.0 - smoothstep(-aa, aa, distFill);
|
|
6916
|
+
if (fillAlpha <= 0.0) { discard; }
|
|
6917
|
+
outFragColor = vec4f(fill.rgb, fill.a * fillAlpha);
|
|
6918
|
+
} else if (fill.a != 0.0) {
|
|
6919
|
+
let fillAlpha = 1.0 - smoothstep(-aa, aa, distFill);
|
|
6920
|
+
let strokeDist = abs(distStroke) - halfStroke;
|
|
6921
|
+
let strokeAlphaMask = 1.0 - smoothstep(-aa, aa, strokeDist);
|
|
6922
|
+
|
|
6923
|
+
if (fillAlpha <= 0.0 && strokeAlphaMask <= 0.0) { discard; }
|
|
6924
|
+
|
|
6925
|
+
let sA = stroke.a * strokeAlphaMask;
|
|
6926
|
+
let fA = fill.a * fillAlpha;
|
|
6927
|
+
let outAlpha = sA + fA * (1.0 - sA);
|
|
6928
|
+
let outCol = stroke.rgb * sA + fill.rgb * fA * (1.0 - sA);
|
|
6929
|
+
outFragColor = vec4f(outCol / max(outAlpha, 1e-5), outAlpha);
|
|
6930
|
+
} else {
|
|
6931
|
+
let strokeDist = abs(distStroke) - halfStroke;
|
|
6932
|
+
let strokeAlpha = 1.0 - smoothstep(-aa, aa, strokeDist);
|
|
6933
|
+
|
|
6934
|
+
if (strokeAlpha <= 0.0) { discard; }
|
|
6935
|
+
outFragColor = vec4f(stroke.rgb, stroke.a * strokeAlpha);
|
|
6936
|
+
}
|
|
6937
|
+
return outFragColor;
|
|
6938
|
+
}
|
|
6939
|
+
`;
|
|
6940
|
+
|
|
6941
|
+
let polygonShader = Q5.device.createShaderModule({
|
|
6942
|
+
label: 'polygonShader',
|
|
6943
|
+
code: $._polygonShaderCode
|
|
6944
|
+
});
|
|
6945
|
+
|
|
6946
|
+
let polygonVertStack = new Float32Array($._isGraphics ? 1000 : 1e7),
|
|
6947
|
+
polygonVertIdx = 0;
|
|
6948
|
+
let polyPtsStack = new Float32Array($._isGraphics ? 1000 : 1e7),
|
|
6949
|
+
polyPtsIdx = 0;
|
|
6950
|
+
|
|
6951
|
+
let polygonVertBuffLayout = {
|
|
6952
|
+
arrayStride: 32, // 8 floats * 4 bytes
|
|
6953
|
+
attributes: [
|
|
6954
|
+
{ format: 'float32x2', offset: 0, shaderLocation: 0 },
|
|
6955
|
+
{ format: 'float32', offset: 8, shaderLocation: 1 },
|
|
6956
|
+
{ format: 'float32', offset: 12, shaderLocation: 2 },
|
|
6957
|
+
{ format: 'float32', offset: 16, shaderLocation: 3 },
|
|
6958
|
+
{ format: 'float32', offset: 20, shaderLocation: 4 },
|
|
6959
|
+
{ format: 'float32', offset: 24, shaderLocation: 5 },
|
|
6960
|
+
{ format: 'float32', offset: 28, shaderLocation: 6 }
|
|
6961
|
+
]
|
|
6962
|
+
};
|
|
6963
|
+
|
|
6964
|
+
let polygonBindGroupLayout = Q5.device.createBindGroupLayout({
|
|
6965
|
+
entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'read-only-storage' } }]
|
|
6966
|
+
});
|
|
6967
|
+
|
|
6968
|
+
let polygonPipelineLayout = Q5.device.createPipelineLayout({
|
|
6969
|
+
label: 'polygonPipelineLayout',
|
|
6970
|
+
bindGroupLayouts: [mainLayout, polygonBindGroupLayout]
|
|
6971
|
+
});
|
|
6972
|
+
|
|
6973
|
+
$._pipelineConfigs[7] = {
|
|
6974
|
+
label: 'polygonPipeline',
|
|
6975
|
+
layout: polygonPipelineLayout,
|
|
6976
|
+
vertex: { module: polygonShader, entryPoint: 'vertexMain', buffers: [null, null, polygonVertBuffLayout] },
|
|
6977
|
+
fragment: {
|
|
6978
|
+
module: polygonShader,
|
|
6979
|
+
entryPoint: 'fragMain',
|
|
6980
|
+
targets: [{ format: 'bgra8unorm', blend: $.blendConfigs['source-over'] }]
|
|
6981
|
+
},
|
|
6982
|
+
primitive: { topology: 'triangle-list' },
|
|
6983
|
+
multisample: { count: 4 }
|
|
6984
|
+
};
|
|
6985
|
+
$._pipelines[7] = Q5.device.createRenderPipeline($._pipelineConfigs[7]);
|
|
6986
|
+
|
|
6987
|
+
const addPolygonVert = (x, y, start, count, fIdx, sIdx, sWeight, mIdx) => {
|
|
6988
|
+
let v = polygonVertStack,
|
|
6989
|
+
i = polygonVertIdx;
|
|
6990
|
+
v[i++] = x;
|
|
6991
|
+
v[i++] = y;
|
|
6992
|
+
v[i++] = start;
|
|
6993
|
+
v[i++] = count;
|
|
6994
|
+
v[i++] = fIdx;
|
|
6995
|
+
v[i++] = sIdx;
|
|
6996
|
+
v[i++] = sWeight;
|
|
6997
|
+
v[i++] = mIdx;
|
|
6998
|
+
polygonVertIdx = i;
|
|
6999
|
+
};
|
|
7000
|
+
|
|
6691
7001
|
$.endShape = (close) => {
|
|
6692
7002
|
if (curveVertices.length > 0) {
|
|
6693
|
-
// duplicate start and end points if necessary
|
|
6694
7003
|
let points = [...curveVertices];
|
|
6695
7004
|
if (points.length < 4) {
|
|
6696
|
-
// duplicate first and last points
|
|
6697
7005
|
while (points.length < 4) {
|
|
6698
7006
|
points.unshift(points[0]);
|
|
6699
7007
|
points.push(points[points.length - 1]);
|
|
6700
7008
|
}
|
|
6701
7009
|
}
|
|
6702
|
-
|
|
6703
|
-
// Use curveSegments to determine step size
|
|
6704
|
-
let step = 1 / curveSegments;
|
|
6705
|
-
|
|
6706
|
-
// calculate catmull-rom spline curve points
|
|
6707
7010
|
for (let i = 0; i < points.length - 3; i++) {
|
|
6708
|
-
let p0 = points[i]
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
for (let
|
|
6714
|
-
let
|
|
6715
|
-
let
|
|
6716
|
-
|
|
7011
|
+
let p0 = points[i],
|
|
7012
|
+
p1 = points[i + 1],
|
|
7013
|
+
p2 = points[i + 2],
|
|
7014
|
+
p3 = points[i + 3];
|
|
7015
|
+
let startT = i === 0 ? 0 : 1;
|
|
7016
|
+
for (let j = startT; j <= curveSegments; j++) {
|
|
7017
|
+
let t = j / curveSegments;
|
|
7018
|
+
let t2 = t * t,
|
|
7019
|
+
t3 = t2 * t;
|
|
6717
7020
|
let x =
|
|
6718
7021
|
0.5 *
|
|
6719
7022
|
(2 * p1.x +
|
|
6720
7023
|
(-p0.x + p2.x) * t +
|
|
6721
7024
|
(2 * p0.x - 5 * p1.x + 4 * p2.x - p3.x) * t2 +
|
|
6722
7025
|
(-p0.x + 3 * p1.x - 3 * p2.x + p3.x) * t3);
|
|
6723
|
-
|
|
6724
7026
|
let y =
|
|
6725
7027
|
0.5 *
|
|
6726
7028
|
(2 * p1.y +
|
|
6727
7029
|
(-p0.y + p2.y) * t +
|
|
6728
7030
|
(2 * p0.y - 5 * p1.y + 4 * p2.y - p3.y) * t2 +
|
|
6729
7031
|
(-p0.y + 3 * p1.y - 3 * p2.y + p3.y) * t3);
|
|
6730
|
-
|
|
6731
|
-
sv.push(x, y, fillIdx, matrixIdx);
|
|
7032
|
+
sv.push(x, y, fillIdx);
|
|
6732
7033
|
shapeVertCount++;
|
|
6733
7034
|
}
|
|
6734
7035
|
}
|
|
6735
7036
|
}
|
|
6736
7037
|
|
|
6737
7038
|
if (!shapeVertCount) return;
|
|
6738
|
-
if (shapeVertCount == 1)
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
if (firstX !== lastX || firstY !== lastY) {
|
|
6752
|
-
sv.push(firstX, firstY, sv[firstIndex + 2], sv[firstIndex + 3]);
|
|
6753
|
-
shapeVertCount++;
|
|
6754
|
-
}
|
|
7039
|
+
if (shapeVertCount == 1) {
|
|
7040
|
+
$.point(sv[0], sv[1]);
|
|
7041
|
+
shapeVertCount = 0;
|
|
7042
|
+
sv = [];
|
|
7043
|
+
curveVertices = [];
|
|
7044
|
+
return;
|
|
7045
|
+
}
|
|
7046
|
+
if (shapeVertCount == 2) {
|
|
7047
|
+
$.line(sv[0], sv[1], sv[3], sv[4]);
|
|
7048
|
+
shapeVertCount = 0;
|
|
7049
|
+
sv = [];
|
|
7050
|
+
curveVertices = [];
|
|
7051
|
+
return;
|
|
6755
7052
|
}
|
|
6756
7053
|
|
|
6757
|
-
if (
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
}
|
|
7054
|
+
if (matrixDirty) saveMatrix();
|
|
7055
|
+
let ti = matrixIdx;
|
|
7056
|
+
|
|
7057
|
+
let isAutoClosed = false;
|
|
7058
|
+
let isClosedPath = false;
|
|
7059
|
+
let isClosedForStroke = false;
|
|
7060
|
+
let firstX = sv[0],
|
|
7061
|
+
firstY = sv[1];
|
|
7062
|
+
let lastX = sv[(shapeVertCount - 1) * 3],
|
|
7063
|
+
lastY = sv[(shapeVertCount - 1) * 3 + 1];
|
|
7064
|
+
|
|
7065
|
+
if (firstX === lastX && firstY === lastY) {
|
|
7066
|
+
isClosedPath = true;
|
|
7067
|
+
isClosedForStroke = true;
|
|
7068
|
+
} else if (close || doFill) {
|
|
7069
|
+
sv.push(firstX, firstY, sv[2]);
|
|
7070
|
+
shapeVertCount++;
|
|
7071
|
+
isAutoClosed = !close;
|
|
7072
|
+
isClosedPath = true;
|
|
7073
|
+
isClosedForStroke = !!close;
|
|
6778
7074
|
}
|
|
6779
7075
|
|
|
6780
|
-
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
7076
|
+
let runSDF = shapeVertCount >= 3 && doStroke && hswScaled > 3;
|
|
7077
|
+
|
|
7078
|
+
if (runSDF) {
|
|
7079
|
+
let fi = doFill ? fillIdx : 0,
|
|
7080
|
+
si = strokeIdx;
|
|
7081
|
+
|
|
7082
|
+
let polyStart = polyPtsIdx / 4,
|
|
7083
|
+
polyCount = isClosedPath ? shapeVertCount - 1 : shapeVertCount;
|
|
7084
|
+
for (let i = 0; i < polyCount; i++) {
|
|
7085
|
+
polyPtsStack[polyPtsIdx++] = sv[i * 3];
|
|
7086
|
+
polyPtsStack[polyPtsIdx++] = sv[i * 3 + 1];
|
|
7087
|
+
polyPtsStack[polyPtsIdx++] = sv[i * 3 + 2];
|
|
7088
|
+
polyPtsStack[polyPtsIdx++] = ti;
|
|
7089
|
+
}
|
|
7090
|
+
|
|
7091
|
+
let minX = Infinity,
|
|
7092
|
+
minY = Infinity,
|
|
7093
|
+
maxX = -Infinity,
|
|
7094
|
+
maxY = -Infinity;
|
|
7095
|
+
for (let i = 0; i < shapeVertCount; i++) {
|
|
7096
|
+
let vx = sv[i * 3],
|
|
7097
|
+
vy = sv[i * 3 + 1];
|
|
7098
|
+
if (vx < minX) minX = vx;
|
|
7099
|
+
if (vx > maxX) maxX = vx;
|
|
7100
|
+
if (vy < minY) minY = vy;
|
|
7101
|
+
if (vy > maxY) maxY = vy;
|
|
7102
|
+
}
|
|
7103
|
+
let padding = sw * 0.5 + 1.0; // padding for stroke and AA
|
|
7104
|
+
minX -= padding;
|
|
7105
|
+
minY -= padding;
|
|
7106
|
+
maxX += padding;
|
|
7107
|
+
maxY += padding;
|
|
7108
|
+
|
|
7109
|
+
// single SDF pass: encode fill-closure in polyCount sign, stroke-closure in strokeWeight sign
|
|
7110
|
+
let passedCount = doFill ? polyCount : -polyCount;
|
|
7111
|
+
let strokeWeightSigned = isClosedForStroke ? sw : -sw;
|
|
7112
|
+
addPolygonVert(minX, minY, polyStart, passedCount, fi, si, strokeWeightSigned, ti);
|
|
7113
|
+
addPolygonVert(maxX, minY, polyStart, passedCount, fi, si, strokeWeightSigned, ti);
|
|
7114
|
+
addPolygonVert(minX, maxY, polyStart, passedCount, fi, si, strokeWeightSigned, ti);
|
|
7115
|
+
|
|
7116
|
+
addPolygonVert(maxX, minY, polyStart, passedCount, fi, si, strokeWeightSigned, ti);
|
|
7117
|
+
addPolygonVert(maxX, maxY, polyStart, passedCount, fi, si, strokeWeightSigned, ti);
|
|
7118
|
+
addPolygonVert(minX, maxY, polyStart, passedCount, fi, si, strokeWeightSigned, ti);
|
|
7119
|
+
|
|
7120
|
+
drawStack.push(polygonPL, 6);
|
|
7121
|
+
} else {
|
|
7122
|
+
if (doFill) {
|
|
7123
|
+
if (shapeVertCount == 5) {
|
|
7124
|
+
// Quads
|
|
7125
|
+
addVert(sv[0], sv[1], sv[2], ti);
|
|
7126
|
+
addVert(sv[3], sv[4], sv[5], ti);
|
|
7127
|
+
addVert(sv[9], sv[10], sv[11], ti);
|
|
7128
|
+
addVert(sv[6], sv[7], sv[8], ti);
|
|
7129
|
+
drawStack.push(shapesPL, 4);
|
|
7130
|
+
} else {
|
|
7131
|
+
// Triangulation fan
|
|
7132
|
+
for (let i = 1; i < shapeVertCount - 1; i++) {
|
|
7133
|
+
let v0 = 0,
|
|
7134
|
+
v1 = i * 3,
|
|
7135
|
+
v2 = (i + 1) * 3;
|
|
7136
|
+
addVert(sv[v0], sv[v0 + 1], sv[v0 + 2], ti);
|
|
7137
|
+
addVert(sv[v1], sv[v1 + 1], sv[v1 + 2], ti);
|
|
7138
|
+
addVert(sv[v2], sv[v2 + 1], sv[v2 + 2], ti);
|
|
7139
|
+
}
|
|
7140
|
+
drawStack.push(shapesPL, (shapeVertCount - 2) * 3);
|
|
7141
|
+
}
|
|
7142
|
+
}
|
|
7143
|
+
if (doStroke) {
|
|
7144
|
+
let maxLines = isAutoClosed ? shapeVertCount - 2 : shapeVertCount - 1;
|
|
7145
|
+
for (let i = 0; i < maxLines; i++) {
|
|
7146
|
+
let v1 = i * 3,
|
|
7147
|
+
v2 = (i + 1) * 3;
|
|
7148
|
+
$.line(sv[v1], sv[v1 + 1], sv[v2], sv[v2 + 1]);
|
|
7149
|
+
}
|
|
6786
7150
|
}
|
|
6787
|
-
let v1 = (shapeVertCount - 1) * 4;
|
|
6788
|
-
let v2 = 0;
|
|
6789
|
-
if (close) $.line(sv[v1], sv[v1 + 1], sv[v2], sv[v2 + 1]);
|
|
6790
7151
|
}
|
|
6791
7152
|
|
|
6792
|
-
// reset for the next shape
|
|
6793
7153
|
shapeVertCount = 0;
|
|
6794
7154
|
sv = [];
|
|
6795
7155
|
curveVertices = [];
|
|
6796
7156
|
};
|
|
6797
7157
|
|
|
6798
|
-
$.curve = (x1, y1, x2, y2, x3, y3, x4, y4) => {
|
|
6799
|
-
$.beginShape();
|
|
6800
|
-
$.curveVertex(x1, y1);
|
|
6801
|
-
$.curveVertex(x2, y2);
|
|
6802
|
-
$.curveVertex(x3, y3);
|
|
6803
|
-
$.curveVertex(x4, y4);
|
|
6804
|
-
$.endShape();
|
|
6805
|
-
};
|
|
6806
|
-
|
|
6807
|
-
$.bezier = (x1, y1, x2, y2, x3, y3, x4, y4) => {
|
|
6808
|
-
$.beginShape();
|
|
6809
|
-
$.vertex(x1, y1);
|
|
6810
|
-
$.bezierVertex(x2, y2, x3, y3, x4, y4);
|
|
6811
|
-
$.endShape();
|
|
6812
|
-
};
|
|
6813
|
-
|
|
6814
7158
|
$.triangle = (x1, y1, x2, y2, x3, y3) => {
|
|
6815
7159
|
$.beginShape();
|
|
6816
7160
|
$.vertex(x1, y1);
|
|
@@ -6828,21 +7172,6 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
|
|
|
6828
7172
|
$.endShape(true);
|
|
6829
7173
|
};
|
|
6830
7174
|
|
|
6831
|
-
function addQuad(x1, y1, x2, y2, x3, y3, x4, y4, ci, ti) {
|
|
6832
|
-
addVert(x1, y1, ci, ti); // v0
|
|
6833
|
-
addVert(x2, y2, ci, ti); // v1
|
|
6834
|
-
addVert(x4, y4, ci, ti); // v3
|
|
6835
|
-
addVert(x3, y3, ci, ti); // v2
|
|
6836
|
-
drawStack.push(shapesPL, 4);
|
|
6837
|
-
}
|
|
6838
|
-
|
|
6839
|
-
$.plane = (x, y, w, h) => {
|
|
6840
|
-
h ??= w;
|
|
6841
|
-
let [l, r, t, b] = calcBox(x, y, w, h, 'center');
|
|
6842
|
-
if (matrixDirty) saveMatrix();
|
|
6843
|
-
addQuad(l, t, r, t, r, b, l, b, fillIdx, matrixIdx);
|
|
6844
|
-
};
|
|
6845
|
-
|
|
6846
7175
|
/* RECT */
|
|
6847
7176
|
|
|
6848
7177
|
let rectPL = 5;
|
|
@@ -7135,7 +7464,21 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
|
|
|
7135
7464
|
};
|
|
7136
7465
|
|
|
7137
7466
|
$.line = (x1, y1, x2, y2) => {
|
|
7138
|
-
if (doStroke)
|
|
7467
|
+
if (!doStroke) return;
|
|
7468
|
+
if (matrixDirty) saveMatrix();
|
|
7469
|
+
|
|
7470
|
+
let dx = x2 - x1,
|
|
7471
|
+
dy = y2 - y1,
|
|
7472
|
+
sqLen = dx * dx + dy * dy;
|
|
7473
|
+
|
|
7474
|
+
if (sqLen === 0) return;
|
|
7475
|
+
|
|
7476
|
+
let len = Math.sqrt(sqLen),
|
|
7477
|
+
ratio = hsw / len,
|
|
7478
|
+
nx = -dy * ratio,
|
|
7479
|
+
ny = dx * ratio;
|
|
7480
|
+
|
|
7481
|
+
addQuad(x1 + nx, y1 + ny, x1 - nx, y1 - ny, x2 - nx, y2 - ny, x2 + nx, y2 + ny, strokeIdx, matrixIdx);
|
|
7139
7482
|
};
|
|
7140
7483
|
|
|
7141
7484
|
/* ELLIPSE */
|
|
@@ -8778,6 +9121,8 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
|
|
|
8778
9121
|
transformsBuffer?.destroy();
|
|
8779
9122
|
colorsBuffer?.destroy();
|
|
8780
9123
|
shapesVertBuff?.destroy();
|
|
9124
|
+
polygonVertBuff?.destroy();
|
|
9125
|
+
polyPtsBuffer?.destroy();
|
|
8781
9126
|
imgVertBuff?.destroy();
|
|
8782
9127
|
charBuffer?.destroy();
|
|
8783
9128
|
textBuffer?.destroy();
|