q5 4.0.0 → 4.1.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/README.md +6 -10
- package/deno.json +2 -2
- package/package.json +2 -2
- package/q5.d.ts +220 -28
- package/q5.js +145 -28
- 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.1
|
|
4
4
|
* @author quinton-ashley
|
|
5
5
|
* @contributors evanalulu, Tezumie, ormaq, Dukemz, LingDong-
|
|
6
6
|
* @license LGPL-3.0
|
|
@@ -47,6 +47,7 @@ function Q5(scope, parent, renderer) {
|
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
$.canvas = $.ctx = $.drawingContext = null;
|
|
50
|
+
$._flippedY = true;
|
|
50
51
|
$.pixels = [];
|
|
51
52
|
let looper = null,
|
|
52
53
|
useRAF = true;
|
|
@@ -469,7 +470,7 @@ if (typeof window == 'object') {
|
|
|
469
470
|
window.WEBGPU = 'webgpu';
|
|
470
471
|
} else global.window = 0;
|
|
471
472
|
|
|
472
|
-
Q5.version = Q5.VERSION = '4.
|
|
473
|
+
Q5.version = Q5.VERSION = '4.1';
|
|
473
474
|
|
|
474
475
|
if (typeof document == 'object') {
|
|
475
476
|
document.addEventListener('DOMContentLoaded', () => {
|
|
@@ -598,6 +599,7 @@ Q5.modules.canvas = ($, q) => {
|
|
|
598
599
|
|
|
599
600
|
if ($._addEventMethods) $._addEventMethods(c);
|
|
600
601
|
|
|
602
|
+
if (!$._isImage) $.resetMatrix();
|
|
601
603
|
$.canvas.ready = true;
|
|
602
604
|
|
|
603
605
|
return rend;
|
|
@@ -3684,7 +3686,7 @@ Q5.modules.input = ($, q) => {
|
|
|
3684
3686
|
let x = (touch.clientX - rect.left) / sx - modX,
|
|
3685
3687
|
y = (touch.clientY - rect.top) / sy - modY;
|
|
3686
3688
|
|
|
3687
|
-
if (
|
|
3689
|
+
if (!$._flippedY) y *= -1;
|
|
3688
3690
|
|
|
3689
3691
|
return {
|
|
3690
3692
|
x,
|
|
@@ -5399,10 +5401,12 @@ struct Q5 {
|
|
|
5399
5401
|
$._buffers = [];
|
|
5400
5402
|
$._texturesToDestroy = [];
|
|
5401
5403
|
|
|
5402
|
-
// local variables used for
|
|
5404
|
+
// local variables used for better performance
|
|
5403
5405
|
|
|
5404
5406
|
// stores pipeline shifts and vertex counts/image indices
|
|
5405
|
-
let drawStack = [];
|
|
5407
|
+
let drawStack = ($._drawStack = []);
|
|
5408
|
+
$._customDrawHandlers = {};
|
|
5409
|
+
$._customBindHandlers = {};
|
|
5406
5410
|
|
|
5407
5411
|
// colors used for each draw call
|
|
5408
5412
|
let colorStack = new Float32Array(1e6);
|
|
@@ -5435,7 +5439,7 @@ struct Q5 {
|
|
|
5435
5439
|
]
|
|
5436
5440
|
});
|
|
5437
5441
|
|
|
5438
|
-
$.
|
|
5442
|
+
$._mainLayout = mainLayout;
|
|
5439
5443
|
|
|
5440
5444
|
let uniformBuffer = Q5.device.createBuffer({
|
|
5441
5445
|
size: 64,
|
|
@@ -5718,19 +5722,22 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
|
|
|
5718
5722
|
matrixIdx = 0,
|
|
5719
5723
|
matrixDirty = false; // tracks if the matrix has been modified
|
|
5720
5724
|
|
|
5725
|
+
$._getMatrixIdx = () => matrixIdx;
|
|
5726
|
+
|
|
5721
5727
|
// 4x4 identity matrix
|
|
5722
5728
|
// prettier-ignore
|
|
5723
5729
|
matrices.push([
|
|
5724
5730
|
1, 0, 0, 0,
|
|
5725
|
-
0, 1, 0, 0,
|
|
5731
|
+
0, -1, 0, 0,
|
|
5726
5732
|
0, 0, 1, 0,
|
|
5727
5733
|
0, 0, 0, 1
|
|
5728
5734
|
]);
|
|
5729
5735
|
|
|
5730
5736
|
transforms.set(matrices[0]);
|
|
5731
5737
|
|
|
5732
|
-
|
|
5733
|
-
|
|
5738
|
+
// default is y-down for q5 WebGPU
|
|
5739
|
+
let flippedY = true,
|
|
5740
|
+
yDir = -1;
|
|
5734
5741
|
|
|
5735
5742
|
$.flipY = () => {
|
|
5736
5743
|
$._flippedY = flippedY = !flippedY;
|
|
@@ -5741,9 +5748,6 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
|
|
|
5741
5748
|
transforms.set(matrices[0], 0);
|
|
5742
5749
|
};
|
|
5743
5750
|
|
|
5744
|
-
// current default is y-down for q5 WebGPU
|
|
5745
|
-
$.flipY();
|
|
5746
|
-
|
|
5747
5751
|
$.translate = (x, y) => {
|
|
5748
5752
|
if (!x && !y) return;
|
|
5749
5753
|
let m = matrix;
|
|
@@ -6354,6 +6358,8 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
|
|
|
6354
6358
|
} else if (curPipelineIndex == 6) {
|
|
6355
6359
|
pass.setIndexBuffer(ellipseIndexBuffer, 'uint16');
|
|
6356
6360
|
pass.setBindGroup(1, ellipseBindGroup);
|
|
6361
|
+
} else if ($._customBindHandlers[curPipelineIndex]) {
|
|
6362
|
+
$._customBindHandlers[curPipelineIndex](pass);
|
|
6357
6363
|
}
|
|
6358
6364
|
}
|
|
6359
6365
|
|
|
@@ -6381,11 +6387,14 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
|
|
|
6381
6387
|
pass.setBindGroup(1, $._textureBindGroups[v]);
|
|
6382
6388
|
pass.draw(4, 1, imageVertOffset);
|
|
6383
6389
|
imageVertOffset += 4;
|
|
6384
|
-
} else {
|
|
6390
|
+
} else if (curPipelineIndex == 1 || curPipelineIndex >= 1000) {
|
|
6385
6391
|
// draw a shape
|
|
6386
6392
|
// v is the number of vertices
|
|
6387
6393
|
pass.draw(v, 1, drawVertOffset);
|
|
6388
6394
|
drawVertOffset += v;
|
|
6395
|
+
} else {
|
|
6396
|
+
let used = $._customDrawHandlers[curPipelineIndex](pass, v, drawStack, i);
|
|
6397
|
+
if (used) i += used;
|
|
6389
6398
|
}
|
|
6390
6399
|
}
|
|
6391
6400
|
};
|
|
@@ -6522,7 +6531,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
|
|
|
6522
6531
|
|
|
6523
6532
|
let shapesPipelineLayout = Q5.device.createPipelineLayout({
|
|
6524
6533
|
label: 'shapesPipelineLayout',
|
|
6525
|
-
bindGroupLayouts:
|
|
6534
|
+
bindGroupLayouts: [mainLayout]
|
|
6526
6535
|
});
|
|
6527
6536
|
|
|
6528
6537
|
$._pipelineConfigs[1] = {
|
|
@@ -6951,7 +6960,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
|
|
|
6951
6960
|
|
|
6952
6961
|
let rectPipelineLayout = Q5.device.createPipelineLayout({
|
|
6953
6962
|
label: 'rectPipelineLayout',
|
|
6954
|
-
bindGroupLayouts: [
|
|
6963
|
+
bindGroupLayouts: [mainLayout, rectBindGroupLayout]
|
|
6955
6964
|
});
|
|
6956
6965
|
|
|
6957
6966
|
$._pipelineConfigs[5] = {
|
|
@@ -7259,7 +7268,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
|
|
|
7259
7268
|
|
|
7260
7269
|
let ellipsePipelineLayout = Q5.device.createPipelineLayout({
|
|
7261
7270
|
label: 'ellipsePipelineLayout',
|
|
7262
|
-
bindGroupLayouts: [
|
|
7271
|
+
bindGroupLayouts: [mainLayout, ellipseBindGroupLayout]
|
|
7263
7272
|
});
|
|
7264
7273
|
|
|
7265
7274
|
$._pipelineConfigs[6] = {
|
|
@@ -7529,12 +7538,12 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
|
|
|
7529
7538
|
|
|
7530
7539
|
let imagePipelineLayout = Q5.device.createPipelineLayout({
|
|
7531
7540
|
label: 'imagePipelineLayout',
|
|
7532
|
-
bindGroupLayouts: [
|
|
7541
|
+
bindGroupLayouts: [mainLayout, textureLayout]
|
|
7533
7542
|
});
|
|
7534
7543
|
|
|
7535
7544
|
let videoPipelineLayout = Q5.device.createPipelineLayout({
|
|
7536
7545
|
label: 'videoPipelineLayout',
|
|
7537
|
-
bindGroupLayouts: [
|
|
7546
|
+
bindGroupLayouts: [mainLayout, videoTextureLayout]
|
|
7538
7547
|
});
|
|
7539
7548
|
|
|
7540
7549
|
$._pipelineConfigs[2] = {
|
|
@@ -8027,7 +8036,7 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
|
|
|
8027
8036
|
});
|
|
8028
8037
|
|
|
8029
8038
|
let fontPipelineLayout = Q5.device.createPipelineLayout({
|
|
8030
|
-
bindGroupLayouts: [
|
|
8039
|
+
bindGroupLayouts: [mainLayout, fontBindGroupLayout, textBindGroupLayout]
|
|
8031
8040
|
});
|
|
8032
8041
|
|
|
8033
8042
|
$._pipelineConfigs[4] = {
|
|
@@ -8536,9 +8545,117 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
|
|
|
8536
8545
|
text: 4000
|
|
8537
8546
|
};
|
|
8538
8547
|
|
|
8539
|
-
$.
|
|
8548
|
+
$._createPipeline = (opt) => {
|
|
8549
|
+
if (typeof opt == 'string') opt = { shader: opt };
|
|
8550
|
+
|
|
8551
|
+
let { label, shader = '', topology = 'triangle-list', cullMode = 'none', blend = 'source-over' } = opt;
|
|
8552
|
+
|
|
8553
|
+
let module;
|
|
8554
|
+
if (opt.module) module = opt.module;
|
|
8555
|
+
else {
|
|
8556
|
+
module = Q5.device.createShaderModule({
|
|
8557
|
+
label: label + 'Shader',
|
|
8558
|
+
code: $._baseShaderCode + shader
|
|
8559
|
+
});
|
|
8560
|
+
}
|
|
8561
|
+
|
|
8562
|
+
// Handle optional custom data buffer and its bind group layout
|
|
8563
|
+
let layout = opt.layout;
|
|
8564
|
+
let _dataBuffer = null;
|
|
8565
|
+
let _dataBindLayout = null;
|
|
8566
|
+
let _dataBindGroup = null;
|
|
8567
|
+
if (opt.data) {
|
|
8568
|
+
_dataBuffer = Q5.device.createBuffer({
|
|
8569
|
+
size: opt.data.byteLength,
|
|
8570
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
|
|
8571
|
+
});
|
|
8572
|
+
_dataBindLayout = Q5.device.createBindGroupLayout({
|
|
8573
|
+
entries: [
|
|
8574
|
+
{
|
|
8575
|
+
binding: 0,
|
|
8576
|
+
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
8577
|
+
buffer: { type: 'read-only-storage' }
|
|
8578
|
+
}
|
|
8579
|
+
]
|
|
8580
|
+
});
|
|
8581
|
+
_dataBindGroup = Q5.device.createBindGroup({
|
|
8582
|
+
layout: _dataBindLayout,
|
|
8583
|
+
entries: [{ binding: 0, resource: { buffer: _dataBuffer } }]
|
|
8584
|
+
});
|
|
8585
|
+
$._buffers.push(_dataBuffer);
|
|
8586
|
+
}
|
|
8587
|
+
|
|
8588
|
+
if (!layout) {
|
|
8589
|
+
if (_dataBindLayout) {
|
|
8590
|
+
layout = Q5.device.createPipelineLayout({
|
|
8591
|
+
bindGroupLayouts: [mainLayout, _dataBindLayout]
|
|
8592
|
+
});
|
|
8593
|
+
} else {
|
|
8594
|
+
layout = Q5.device.createPipelineLayout({
|
|
8595
|
+
bindGroupLayouts: [mainLayout]
|
|
8596
|
+
});
|
|
8597
|
+
}
|
|
8598
|
+
}
|
|
8599
|
+
|
|
8600
|
+
let pipelineConfig = {
|
|
8601
|
+
label: label + 'Pipeline',
|
|
8602
|
+
layout,
|
|
8603
|
+
vertex: {
|
|
8604
|
+
module,
|
|
8605
|
+
entryPoint: 'vertexMain'
|
|
8606
|
+
},
|
|
8607
|
+
fragment: {
|
|
8608
|
+
module,
|
|
8609
|
+
entryPoint: 'fragMain',
|
|
8610
|
+
targets: [
|
|
8611
|
+
{
|
|
8612
|
+
format: 'bgra8unorm',
|
|
8613
|
+
blend: $.blendConfigs[blend]
|
|
8614
|
+
}
|
|
8615
|
+
]
|
|
8616
|
+
},
|
|
8617
|
+
primitive: {
|
|
8618
|
+
topology,
|
|
8619
|
+
cullMode
|
|
8620
|
+
},
|
|
8621
|
+
multisample: { count: 4 }
|
|
8622
|
+
};
|
|
8623
|
+
|
|
8624
|
+
let id = $._pipelines.length;
|
|
8625
|
+
$._pipelineConfigs[id] = pipelineConfig;
|
|
8626
|
+
$._pipelines[id] = Q5.device.createRenderPipeline(pipelineConfig);
|
|
8627
|
+
|
|
8628
|
+
// If we created a data buffer/bind group, register a bind handler
|
|
8629
|
+
if (_dataBindGroup) {
|
|
8630
|
+
$._customBindHandlers[id] = (pass) => {
|
|
8631
|
+
Q5.device.queue.writeBuffer(_dataBuffer, 0, opt.data);
|
|
8632
|
+
pass.setBindGroup(1, _dataBindGroup);
|
|
8633
|
+
};
|
|
8634
|
+
}
|
|
8635
|
+
|
|
8636
|
+
return id;
|
|
8637
|
+
};
|
|
8638
|
+
|
|
8639
|
+
$.createShader = (code, type = 'shapes', options = {}) => {
|
|
8540
8640
|
code = code.trim();
|
|
8541
8641
|
|
|
8642
|
+
// create custom shader
|
|
8643
|
+
if (!pipelineTypes.includes(type)) {
|
|
8644
|
+
if (options instanceof Float32Array) options = { data: options };
|
|
8645
|
+
options.shader = code;
|
|
8646
|
+
options.label = type;
|
|
8647
|
+
|
|
8648
|
+
let id = $._createPipeline(options);
|
|
8649
|
+
|
|
8650
|
+
let shader = $._pipelineConfigs[id].vertex.module;
|
|
8651
|
+
shader.type = type;
|
|
8652
|
+
shader.pipelineIndex = id;
|
|
8653
|
+
$._customDrawHandlers[id] ??= (pass, count) => {
|
|
8654
|
+
pass.draw(count, 1, 0, 0);
|
|
8655
|
+
};
|
|
8656
|
+
return shader;
|
|
8657
|
+
}
|
|
8658
|
+
|
|
8542
8659
|
// default shader code
|
|
8543
8660
|
let def = $['_' + type + 'ShaderCode'];
|
|
8544
8661
|
|
|
@@ -8576,11 +8693,11 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
|
|
|
8576
8693
|
return shader;
|
|
8577
8694
|
};
|
|
8578
8695
|
|
|
8579
|
-
$.
|
|
8580
|
-
$.createFrameShader = (code) => $.
|
|
8581
|
-
$.createImageShader = (code) => $.
|
|
8582
|
-
$.createVideoShader = (code) => $.
|
|
8583
|
-
$.createTextShader = (code) => $.
|
|
8696
|
+
$.createShapesShader = $.createShader;
|
|
8697
|
+
$.createFrameShader = (code) => $.createShader(code, 'frame');
|
|
8698
|
+
$.createImageShader = (code) => $.createShader(code, 'image');
|
|
8699
|
+
$.createVideoShader = (code) => $.createShader(code, 'video');
|
|
8700
|
+
$.createTextShader = (code) => $.createShader(code, 'text');
|
|
8584
8701
|
|
|
8585
8702
|
$.shader = (shader) => {
|
|
8586
8703
|
let type = shader.type;
|
|
@@ -8650,7 +8767,7 @@ Q5.MAX_TEXTS = 10000;
|
|
|
8650
8767
|
Q5.initWebGPU = async () => {
|
|
8651
8768
|
if (!navigator.gpu) {
|
|
8652
8769
|
console.warn('q5 WebGPU not supported on this browser! Use Google Chrome or Edge.');
|
|
8653
|
-
return
|
|
8770
|
+
return;
|
|
8654
8771
|
}
|
|
8655
8772
|
|
|
8656
8773
|
// fn can only be called once
|
|
@@ -8665,7 +8782,7 @@ Q5.initWebGPU = async () => {
|
|
|
8665
8782
|
|
|
8666
8783
|
if (!adapter) {
|
|
8667
8784
|
console.warn('q5 WebGPU could not start! No appropriate GPUAdapter found, Vulkan may need to be enabled.');
|
|
8668
|
-
return
|
|
8785
|
+
return;
|
|
8669
8786
|
}
|
|
8670
8787
|
|
|
8671
8788
|
let device = await adapter.requestDevice();
|
|
@@ -8674,7 +8791,7 @@ Q5.initWebGPU = async () => {
|
|
|
8674
8791
|
device.limits.maxStorageBuffersInVertexStage ?? device.limits.maxStorageBuffersPerShaderStage;
|
|
8675
8792
|
if (vertexStorageLimit < 3) {
|
|
8676
8793
|
console.warn('q5 WebGPU requires vertex storage buffers, which are not supported by this device.');
|
|
8677
|
-
return
|
|
8794
|
+
return;
|
|
8678
8795
|
}
|
|
8679
8796
|
|
|
8680
8797
|
// Update to fit device limits
|