q5 2.12.10 → 2.13.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/package.json +1 -1
- package/q5.d.ts +6 -5
- package/q5.js +212 -165
- package/q5.min.js +2 -2
- package/src/q5-2d-canvas.js +11 -3
- package/src/q5-2d-image.js +38 -33
- package/src/q5-canvas.js +1 -0
- package/src/q5-core.js +1 -1
- package/src/q5-webgpu-canvas.js +69 -50
- package/src/q5-webgpu-drawing.js +9 -9
- package/src/q5-webgpu-image.js +74 -58
- package/src/q5-webgpu-text.js +9 -11
package/q5.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* q5.js
|
|
3
|
-
* @version 2.
|
|
3
|
+
* @version 2.13
|
|
4
4
|
* @author quinton-ashley, Tezumie, and LingDong-
|
|
5
5
|
* @license LGPL-3.0
|
|
6
6
|
* @class Q5
|
|
@@ -575,6 +575,7 @@ Q5.modules.canvas = ($, q) => {
|
|
|
575
575
|
'_strokeSet',
|
|
576
576
|
'_fillSet',
|
|
577
577
|
'_shadow',
|
|
578
|
+
'_doShadow',
|
|
578
579
|
'_shadowOffsetX',
|
|
579
580
|
'_shadowOffsetY',
|
|
580
581
|
'_shadowBlur',
|
|
@@ -781,6 +782,7 @@ Q5.renderers.q2d.canvas = ($, q) => {
|
|
|
781
782
|
$.noStroke = () => ($._doStroke = false);
|
|
782
783
|
$.opacity = (a) => ($.ctx.globalAlpha = a);
|
|
783
784
|
|
|
785
|
+
$._doShadow = false;
|
|
784
786
|
$._shadowOffsetX = $._shadowOffsetY = $._shadowBlur = 10;
|
|
785
787
|
|
|
786
788
|
$.shadow = function (c) {
|
|
@@ -791,6 +793,7 @@ Q5.renderers.q2d.canvas = ($, q) => {
|
|
|
791
793
|
}
|
|
792
794
|
}
|
|
793
795
|
$.ctx.shadowColor = $._shadow = c.toString();
|
|
796
|
+
$._doShadow = true;
|
|
794
797
|
|
|
795
798
|
$.ctx.shadowOffsetX ||= $._shadowOffsetX;
|
|
796
799
|
$.ctx.shadowOffsetY ||= $._shadowOffsetY;
|
|
@@ -804,6 +807,7 @@ Q5.renderers.q2d.canvas = ($, q) => {
|
|
|
804
807
|
};
|
|
805
808
|
|
|
806
809
|
$.noShadow = () => {
|
|
810
|
+
$._doShadow = false;
|
|
807
811
|
$.ctx.shadowOffsetX = $.ctx.shadowOffsetY = $.ctx.shadowBlur = 0;
|
|
808
812
|
};
|
|
809
813
|
|
|
@@ -845,13 +849,18 @@ Q5.renderers.q2d.canvas = ($, q) => {
|
|
|
845
849
|
$.pushMatrix = () => $.ctx.save();
|
|
846
850
|
$.popMatrix = () => $.ctx.restore();
|
|
847
851
|
|
|
852
|
+
let _popStyles = $.popStyles;
|
|
853
|
+
|
|
848
854
|
$.popStyles = () => {
|
|
849
|
-
|
|
850
|
-
for (let s of $._styleNames) $[s] = styles[s];
|
|
855
|
+
_popStyles();
|
|
851
856
|
|
|
852
857
|
$.ctx.fillStyle = $._fill;
|
|
853
858
|
$.ctx.strokeStyle = $._stroke;
|
|
854
859
|
$.ctx.lineWidth = $._strokeWeight;
|
|
860
|
+
$.ctx.shadowColor = $._shadow;
|
|
861
|
+
$.ctx.shadowOffsetX = $._doShadow ? $._shadowOffsetX : 0;
|
|
862
|
+
$.ctx.shadowOffsetY = $._doShadow ? $._shadowOffsetY : 0;
|
|
863
|
+
$.ctx.shadowBlur = $._doShadow ? $._shadowBlur : 0;
|
|
855
864
|
};
|
|
856
865
|
|
|
857
866
|
$.push = () => {
|
|
@@ -860,7 +869,7 @@ Q5.renderers.q2d.canvas = ($, q) => {
|
|
|
860
869
|
};
|
|
861
870
|
$.pop = () => {
|
|
862
871
|
$.ctx.restore();
|
|
863
|
-
|
|
872
|
+
_popStyles();
|
|
864
873
|
};
|
|
865
874
|
|
|
866
875
|
$.createCapture = (x) => {
|
|
@@ -1419,42 +1428,47 @@ Q5.renderers.q2d.image = ($, q) => {
|
|
|
1419
1428
|
};
|
|
1420
1429
|
|
|
1421
1430
|
$.filter = (type, value) => {
|
|
1422
|
-
|
|
1431
|
+
$.ctx.save();
|
|
1432
|
+
|
|
1423
1433
|
let f = '';
|
|
1424
|
-
if (typeof type === 'string') {
|
|
1425
|
-
f = type;
|
|
1426
|
-
} else if (type === Q5.GRAY) {
|
|
1427
|
-
f = `saturate(0%)`;
|
|
1428
|
-
} else if (type === Q5.INVERT) {
|
|
1429
|
-
f = `invert(100%)`;
|
|
1430
|
-
} else if (type === Q5.BLUR) {
|
|
1431
|
-
let r = Math.ceil(value * $._pixelDensity) || 1;
|
|
1432
|
-
f = `blur(${r}px)`;
|
|
1433
|
-
} else if (type === Q5.THRESHOLD) {
|
|
1434
|
-
value ??= 0.5;
|
|
1435
|
-
let b = Math.floor((0.5 / Math.max(value, 0.00001)) * 100);
|
|
1436
|
-
f = `saturate(0%) brightness(${b}%) contrast(1000000%)`;
|
|
1437
|
-
} else if (type === Q5.SEPIA) {
|
|
1438
|
-
f = `sepia(${value ?? 1})`;
|
|
1439
|
-
} else if (type === Q5.BRIGHTNESS) {
|
|
1440
|
-
f = `brightness(${value ?? 1})`;
|
|
1441
|
-
} else if (type === Q5.SATURATION) {
|
|
1442
|
-
f = `saturate(${value ?? 1})`;
|
|
1443
|
-
} else if (type === Q5.CONTRAST) {
|
|
1444
|
-
f = `contrast(${value ?? 1})`;
|
|
1445
|
-
} else if (type === Q5.HUE_ROTATE) {
|
|
1446
|
-
let unit = $._angleMode === 0 ? 'rad' : 'deg';
|
|
1447
|
-
f = `hue-rotate(${value}${unit})`;
|
|
1448
|
-
} else {
|
|
1449
|
-
$._softFilter(type, value);
|
|
1450
|
-
return;
|
|
1451
|
-
}
|
|
1452
1434
|
|
|
1453
|
-
$.ctx.
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1435
|
+
if ($.ctx.filter) {
|
|
1436
|
+
if (typeof type == 'string') {
|
|
1437
|
+
f = type;
|
|
1438
|
+
} else if (type == Q5.GRAY) {
|
|
1439
|
+
f = `saturate(0%)`;
|
|
1440
|
+
} else if (type == Q5.INVERT) {
|
|
1441
|
+
f = `invert(100%)`;
|
|
1442
|
+
} else if (type == Q5.BLUR) {
|
|
1443
|
+
let r = Math.ceil(value * $._pixelDensity) || 1;
|
|
1444
|
+
f = `blur(${r}px)`;
|
|
1445
|
+
} else if (type == Q5.THRESHOLD) {
|
|
1446
|
+
value ??= 0.5;
|
|
1447
|
+
let b = Math.floor((0.5 / Math.max(value, 0.00001)) * 100);
|
|
1448
|
+
f = `saturate(0%) brightness(${b}%) contrast(1000000%)`;
|
|
1449
|
+
} else if (type == Q5.SEPIA) {
|
|
1450
|
+
f = `sepia(${value ?? 1})`;
|
|
1451
|
+
} else if (type == Q5.BRIGHTNESS) {
|
|
1452
|
+
f = `brightness(${value ?? 1})`;
|
|
1453
|
+
} else if (type == Q5.SATURATION) {
|
|
1454
|
+
f = `saturate(${value ?? 1})`;
|
|
1455
|
+
} else if (type == Q5.CONTRAST) {
|
|
1456
|
+
f = `contrast(${value ?? 1})`;
|
|
1457
|
+
} else if (type == Q5.HUE_ROTATE) {
|
|
1458
|
+
let unit = $._angleMode == 0 ? 'rad' : 'deg';
|
|
1459
|
+
f = `hue-rotate(${value}${unit})`;
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
if (f) {
|
|
1463
|
+
$.ctx.filter = f;
|
|
1464
|
+
if ($.ctx.filter == 'none') {
|
|
1465
|
+
throw new Error(`Invalid filter format: ${type}`);
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1457
1468
|
}
|
|
1469
|
+
|
|
1470
|
+
if (!f) $._softFilter(type, value);
|
|
1471
|
+
|
|
1458
1472
|
$.ctx.globalCompositeOperation = 'source-over';
|
|
1459
1473
|
$.ctx.drawImage($.canvas, 0, 0, $.canvas.w, $.canvas.h);
|
|
1460
1474
|
$.ctx.restore();
|
|
@@ -3580,6 +3594,9 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
3580
3594
|
c.width = $.width = 500;
|
|
3581
3595
|
c.height = $.height = 500;
|
|
3582
3596
|
|
|
3597
|
+
// q2d graphics context
|
|
3598
|
+
$._g = $.createGraphics(1, 1);
|
|
3599
|
+
|
|
3583
3600
|
if ($.colorMode) $.colorMode('rgb', 1);
|
|
3584
3601
|
|
|
3585
3602
|
let pass,
|
|
@@ -3715,7 +3732,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
3715
3732
|
};
|
|
3716
3733
|
|
|
3717
3734
|
$._stroke = 0;
|
|
3718
|
-
$._fill = 1;
|
|
3735
|
+
$._fill = $._tint = 1;
|
|
3719
3736
|
$._doFill = $._doStroke = true;
|
|
3720
3737
|
|
|
3721
3738
|
$.fill = (r, g, b, a) => {
|
|
@@ -3728,42 +3745,51 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
3728
3745
|
$._doStroke = $._strokeSet = true;
|
|
3729
3746
|
$._stroke = colorIndex;
|
|
3730
3747
|
};
|
|
3748
|
+
$.tint = (r, g, b, a) => {
|
|
3749
|
+
addColor(r, g, b, a);
|
|
3750
|
+
$._tint = colorIndex;
|
|
3751
|
+
};
|
|
3731
3752
|
|
|
3732
3753
|
$.noFill = () => ($._doFill = false);
|
|
3733
3754
|
$.noStroke = () => ($._doStroke = false);
|
|
3755
|
+
$.noTint = () => ($._tint = 1);
|
|
3734
3756
|
|
|
3735
3757
|
$._strokeWeight = 1;
|
|
3736
3758
|
$.strokeWeight = (v) => ($._strokeWeight = Math.abs(v));
|
|
3737
3759
|
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
0, 1, 0, 0,
|
|
3745
|
-
0, 0, 1, 0,
|
|
3746
|
-
0, 0, 0, 1
|
|
3747
|
-
];
|
|
3748
|
-
$._transformIndex = 0;
|
|
3749
|
-
};
|
|
3750
|
-
$.resetMatrix();
|
|
3760
|
+
const MAX_TRANSFORMS = 1e7, // or whatever maximum you need
|
|
3761
|
+
MATRIX_SIZE = 16, // 4x4 matrix
|
|
3762
|
+
transforms = new Float32Array(MAX_TRANSFORMS * MATRIX_SIZE),
|
|
3763
|
+
matrices = [],
|
|
3764
|
+
matricesIndexStack = [];
|
|
3765
|
+
let matrix;
|
|
3751
3766
|
|
|
3752
3767
|
// tracks if the matrix has been modified
|
|
3753
3768
|
$._matrixDirty = false;
|
|
3754
3769
|
|
|
3755
|
-
//
|
|
3756
|
-
|
|
3770
|
+
// initialize with a 4x4 identity matrix
|
|
3771
|
+
// prettier-ignore
|
|
3772
|
+
matrices.push([
|
|
3773
|
+
1, 0, 0, 0,
|
|
3774
|
+
0, 1, 0, 0,
|
|
3775
|
+
0, 0, 1, 0,
|
|
3776
|
+
0, 0, 0, 1
|
|
3777
|
+
]);
|
|
3757
3778
|
|
|
3758
|
-
|
|
3759
|
-
|
|
3779
|
+
transforms.set(matrices[0]);
|
|
3780
|
+
|
|
3781
|
+
$.resetMatrix = () => {
|
|
3782
|
+
matrix = matrices[0].slice();
|
|
3783
|
+
$._matrixIndex = 0;
|
|
3784
|
+
};
|
|
3785
|
+
$.resetMatrix();
|
|
3760
3786
|
|
|
3761
3787
|
$.translate = (x, y, z) => {
|
|
3762
3788
|
if (!x && !y && !z) return;
|
|
3763
3789
|
// update the translation values
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3790
|
+
matrix[12] += x;
|
|
3791
|
+
matrix[13] -= y;
|
|
3792
|
+
matrix[14] += z || 0;
|
|
3767
3793
|
$._matrixDirty = true;
|
|
3768
3794
|
};
|
|
3769
3795
|
|
|
@@ -3774,7 +3800,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
3774
3800
|
let cosR = Math.cos(a);
|
|
3775
3801
|
let sinR = Math.sin(a);
|
|
3776
3802
|
|
|
3777
|
-
let m =
|
|
3803
|
+
let m = matrix;
|
|
3778
3804
|
|
|
3779
3805
|
let m0 = m[0],
|
|
3780
3806
|
m1 = m[1],
|
|
@@ -3801,7 +3827,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
3801
3827
|
$.scale = (x = 1, y, z = 1) => {
|
|
3802
3828
|
y ??= x;
|
|
3803
3829
|
|
|
3804
|
-
let m =
|
|
3830
|
+
let m = matrix;
|
|
3805
3831
|
|
|
3806
3832
|
m[0] *= x;
|
|
3807
3833
|
m[1] *= x;
|
|
@@ -3825,13 +3851,13 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
3825
3851
|
|
|
3826
3852
|
let tanAng = Math.tan(ang);
|
|
3827
3853
|
|
|
3828
|
-
let m0 =
|
|
3829
|
-
m1 =
|
|
3830
|
-
m4 =
|
|
3831
|
-
m5 =
|
|
3854
|
+
let m0 = matrix[0],
|
|
3855
|
+
m1 = matrix[1],
|
|
3856
|
+
m4 = matrix[4],
|
|
3857
|
+
m5 = matrix[5];
|
|
3832
3858
|
|
|
3833
|
-
|
|
3834
|
-
|
|
3859
|
+
matrix[0] = m0 + m4 * tanAng;
|
|
3860
|
+
matrix[1] = m1 + m5 * tanAng;
|
|
3835
3861
|
|
|
3836
3862
|
$._matrixDirty = true;
|
|
3837
3863
|
};
|
|
@@ -3842,13 +3868,13 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
3842
3868
|
|
|
3843
3869
|
let tanAng = Math.tan(ang);
|
|
3844
3870
|
|
|
3845
|
-
let m0 =
|
|
3846
|
-
m1 =
|
|
3847
|
-
m4 =
|
|
3848
|
-
m5 =
|
|
3871
|
+
let m0 = matrix[0],
|
|
3872
|
+
m1 = matrix[1],
|
|
3873
|
+
m4 = matrix[4],
|
|
3874
|
+
m5 = matrix[5];
|
|
3849
3875
|
|
|
3850
|
-
|
|
3851
|
-
|
|
3876
|
+
matrix[4] = m4 + m0 * tanAng;
|
|
3877
|
+
matrix[5] = m5 + m1 * tanAng;
|
|
3852
3878
|
|
|
3853
3879
|
$._matrixDirty = true;
|
|
3854
3880
|
};
|
|
@@ -3866,31 +3892,32 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
3866
3892
|
}
|
|
3867
3893
|
|
|
3868
3894
|
// overwrite the current transformation matrix
|
|
3869
|
-
|
|
3895
|
+
matrix = m.slice();
|
|
3870
3896
|
$._matrixDirty = true;
|
|
3871
3897
|
};
|
|
3872
3898
|
|
|
3873
3899
|
// function to save the current matrix state if dirty
|
|
3874
3900
|
$._saveMatrix = () => {
|
|
3875
|
-
|
|
3876
|
-
$.
|
|
3901
|
+
transforms.set(matrix, matrices.length * MATRIX_SIZE);
|
|
3902
|
+
$._matrixIndex = matrices.length;
|
|
3903
|
+
matrices.push(matrix.slice());
|
|
3877
3904
|
$._matrixDirty = false;
|
|
3878
3905
|
};
|
|
3879
3906
|
|
|
3880
3907
|
// push the current matrix index onto the stack
|
|
3881
3908
|
$.pushMatrix = () => {
|
|
3882
3909
|
if ($._matrixDirty) $._saveMatrix();
|
|
3883
|
-
|
|
3910
|
+
matricesIndexStack.push($._matrixIndex);
|
|
3884
3911
|
};
|
|
3885
3912
|
|
|
3886
3913
|
$.popMatrix = () => {
|
|
3887
|
-
if (
|
|
3914
|
+
if (!matricesIndexStack.length) {
|
|
3888
3915
|
return console.warn('Matrix index stack is empty!');
|
|
3889
3916
|
}
|
|
3890
3917
|
// pop the last matrix index and set it as the current matrix index
|
|
3891
|
-
let idx =
|
|
3892
|
-
|
|
3893
|
-
$.
|
|
3918
|
+
let idx = matricesIndexStack.pop();
|
|
3919
|
+
matrix = matrices[idx].slice();
|
|
3920
|
+
$._matrixIndex = idx;
|
|
3894
3921
|
$._matrixDirty = false;
|
|
3895
3922
|
};
|
|
3896
3923
|
|
|
@@ -4015,14 +4042,14 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
4015
4042
|
};
|
|
4016
4043
|
|
|
4017
4044
|
$._render = () => {
|
|
4018
|
-
if (
|
|
4045
|
+
if (matrices.length > 1 || !$._transformBindGroup) {
|
|
4019
4046
|
let transformBuffer = Q5.device.createBuffer({
|
|
4020
|
-
size:
|
|
4047
|
+
size: matrices.length * MATRIX_SIZE * 4, // 4 bytes per float
|
|
4021
4048
|
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
|
|
4022
4049
|
mappedAtCreation: true
|
|
4023
4050
|
});
|
|
4024
4051
|
|
|
4025
|
-
new Float32Array(transformBuffer.getMappedRange()).set(
|
|
4052
|
+
new Float32Array(transformBuffer.getMappedRange()).set(transforms.slice(0, matrices.length * MATRIX_SIZE));
|
|
4026
4053
|
transformBuffer.unmap();
|
|
4027
4054
|
|
|
4028
4055
|
$._transformBindGroup = Q5.device.createBindGroup({
|
|
@@ -4050,7 +4077,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
4050
4077
|
entries: [{ binding: 0, resource: { buffer: colorsBuffer } }]
|
|
4051
4078
|
});
|
|
4052
4079
|
|
|
4053
|
-
|
|
4080
|
+
pass.setBindGroup(1, $._colorsBindGroup);
|
|
4054
4081
|
|
|
4055
4082
|
for (let m of $._hooks.preRender) m();
|
|
4056
4083
|
|
|
@@ -4074,6 +4101,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
4074
4101
|
pass.draw(v, 1, drawVertOffset);
|
|
4075
4102
|
drawVertOffset += v;
|
|
4076
4103
|
} else if (curPipelineIndex == 1) {
|
|
4104
|
+
// let vertCount = drawStack[i + 2];
|
|
4077
4105
|
// draw images
|
|
4078
4106
|
if (curTextureIndex != v) {
|
|
4079
4107
|
// v is the texture index
|
|
@@ -4081,6 +4109,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
4081
4109
|
}
|
|
4082
4110
|
pass.draw(4, 1, imageVertOffset);
|
|
4083
4111
|
imageVertOffset += 4;
|
|
4112
|
+
// i++;
|
|
4084
4113
|
} else if (curPipelineIndex == 2) {
|
|
4085
4114
|
// draw text
|
|
4086
4115
|
let o = drawStack[i + 2];
|
|
@@ -4109,8 +4138,9 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
4109
4138
|
colorIndex = 1;
|
|
4110
4139
|
colorStackIndex = 8;
|
|
4111
4140
|
rotation = 0;
|
|
4112
|
-
|
|
4113
|
-
|
|
4141
|
+
transforms.length = MATRIX_SIZE;
|
|
4142
|
+
matrices.length = 1;
|
|
4143
|
+
matricesIndexStack.length = 0;
|
|
4114
4144
|
};
|
|
4115
4145
|
};
|
|
4116
4146
|
|
|
@@ -4121,7 +4151,10 @@ Q5.initWebGPU = async () => {
|
|
|
4121
4151
|
}
|
|
4122
4152
|
if (!Q5.device) {
|
|
4123
4153
|
let adapter = await navigator.gpu.requestAdapter();
|
|
4124
|
-
if (!adapter)
|
|
4154
|
+
if (!adapter) {
|
|
4155
|
+
console.warn('q5 WebGPU could not start! No appropriate GPUAdapter found, vulkan may need to be enabled.');
|
|
4156
|
+
return false;
|
|
4157
|
+
}
|
|
4125
4158
|
Q5.device = await adapter.requestDevice();
|
|
4126
4159
|
}
|
|
4127
4160
|
return true;
|
|
@@ -4146,7 +4179,7 @@ Q5.renderers.webgpu.drawing = ($, q) => {
|
|
|
4146
4179
|
struct VertexInput {
|
|
4147
4180
|
@location(0) pos: vec2f,
|
|
4148
4181
|
@location(1) colorIndex: f32,
|
|
4149
|
-
@location(2)
|
|
4182
|
+
@location(2) matrixIndex: f32
|
|
4150
4183
|
}
|
|
4151
4184
|
struct VertexOutput {
|
|
4152
4185
|
@builtin(position) position: vec4f,
|
|
@@ -4165,7 +4198,7 @@ struct Uniforms {
|
|
|
4165
4198
|
@vertex
|
|
4166
4199
|
fn vertexMain(input: VertexInput) -> VertexOutput {
|
|
4167
4200
|
var vert = vec4f(input.pos, 0.0, 1.0);
|
|
4168
|
-
vert = transforms[i32(input.
|
|
4201
|
+
vert = transforms[i32(input.matrixIndex)] * vert;
|
|
4169
4202
|
vert.x /= uniforms.halfWidth;
|
|
4170
4203
|
vert.y /= uniforms.halfHeight;
|
|
4171
4204
|
|
|
@@ -4192,7 +4225,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4192
4225
|
attributes: [
|
|
4193
4226
|
{ format: 'float32x2', offset: 0, shaderLocation: 0 }, // position
|
|
4194
4227
|
{ format: 'float32', offset: 8, shaderLocation: 1 }, // colorIndex
|
|
4195
|
-
{ format: 'float32', offset: 12, shaderLocation: 2 } //
|
|
4228
|
+
{ format: 'float32', offset: 12, shaderLocation: 2 } // matrixIndex
|
|
4196
4229
|
]
|
|
4197
4230
|
};
|
|
4198
4231
|
|
|
@@ -4346,7 +4379,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4346
4379
|
let [l, r, t, b] = $._calcBox(x, y, w, h, $._rectMode);
|
|
4347
4380
|
let ci, ti;
|
|
4348
4381
|
if ($._matrixDirty) $._saveMatrix();
|
|
4349
|
-
ti = $.
|
|
4382
|
+
ti = $._matrixIndex;
|
|
4350
4383
|
|
|
4351
4384
|
if ($._doFill) {
|
|
4352
4385
|
ci = $._fill;
|
|
@@ -4420,7 +4453,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4420
4453
|
let b = w == h ? a : Math.max(h, 1) / 2;
|
|
4421
4454
|
|
|
4422
4455
|
if ($._matrixDirty) $._saveMatrix();
|
|
4423
|
-
let ti = $.
|
|
4456
|
+
let ti = $._matrixIndex;
|
|
4424
4457
|
|
|
4425
4458
|
if ($._doFill) {
|
|
4426
4459
|
addEllipse(x, y, a, b, n, $._fill, ti);
|
|
@@ -4436,7 +4469,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4436
4469
|
|
|
4437
4470
|
$.point = (x, y) => {
|
|
4438
4471
|
if ($._matrixDirty) $._saveMatrix();
|
|
4439
|
-
let ti = $.
|
|
4472
|
+
let ti = $._matrixIndex,
|
|
4440
4473
|
ci = $._stroke,
|
|
4441
4474
|
sw = $._strokeWeight;
|
|
4442
4475
|
|
|
@@ -4456,7 +4489,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4456
4489
|
|
|
4457
4490
|
$.line = (x1, y1, x2, y2) => {
|
|
4458
4491
|
if ($._matrixDirty) $._saveMatrix();
|
|
4459
|
-
let ti = $.
|
|
4492
|
+
let ti = $._matrixIndex,
|
|
4460
4493
|
ci = $._stroke,
|
|
4461
4494
|
sw = $._strokeWeight,
|
|
4462
4495
|
hsw = sw / 2;
|
|
@@ -4491,7 +4524,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4491
4524
|
|
|
4492
4525
|
$.vertex = (x, y) => {
|
|
4493
4526
|
if ($._matrixDirty) $._saveMatrix();
|
|
4494
|
-
sv.push(x, -y, $._fill, $.
|
|
4527
|
+
sv.push(x, -y, $._fill, $._matrixIndex);
|
|
4495
4528
|
shapeVertCount++;
|
|
4496
4529
|
};
|
|
4497
4530
|
|
|
@@ -4536,7 +4569,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4536
4569
|
(2 * p0.y - 5 * p1.y + 4 * p2.y - p3.y) * t2 +
|
|
4537
4570
|
(-p0.y + 3 * p1.y - 3 * p2.y + p3.y) * t3);
|
|
4538
4571
|
|
|
4539
|
-
sv.push(x, y, $._fill, $.
|
|
4572
|
+
sv.push(x, y, $._fill, $._matrixIndex);
|
|
4540
4573
|
shapeVertCount++;
|
|
4541
4574
|
}
|
|
4542
4575
|
}
|
|
@@ -4654,14 +4687,22 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4654
4687
|
};
|
|
4655
4688
|
Q5.renderers.webgpu.image = ($, q) => {
|
|
4656
4689
|
$._textureBindGroups = [];
|
|
4657
|
-
let vertexStack =
|
|
4690
|
+
let vertexStack = new Float32Array(1e7),
|
|
4691
|
+
vertIndex = 0;
|
|
4658
4692
|
|
|
4659
|
-
let
|
|
4660
|
-
label: '
|
|
4693
|
+
let imageShader = Q5.device.createShaderModule({
|
|
4694
|
+
label: 'imageShader',
|
|
4661
4695
|
code: `
|
|
4696
|
+
struct VertexInput {
|
|
4697
|
+
@location(0) pos: vec2f,
|
|
4698
|
+
@location(1) texCoord: vec2f,
|
|
4699
|
+
@location(2) tintIndex: f32,
|
|
4700
|
+
@location(3) matrixIndex: f32
|
|
4701
|
+
}
|
|
4662
4702
|
struct VertexOutput {
|
|
4663
4703
|
@builtin(position) position: vec4f,
|
|
4664
|
-
@location(0) texCoord: vec2f
|
|
4704
|
+
@location(0) texCoord: vec2f,
|
|
4705
|
+
@location(1) tintIndex: f32
|
|
4665
4706
|
}
|
|
4666
4707
|
struct Uniforms {
|
|
4667
4708
|
halfWidth: f32,
|
|
@@ -4671,31 +4712,33 @@ struct Uniforms {
|
|
|
4671
4712
|
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
|
4672
4713
|
@group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;
|
|
4673
4714
|
|
|
4715
|
+
@group(1) @binding(0) var<storage> colors : array<vec4f>;
|
|
4716
|
+
|
|
4717
|
+
@group(2) @binding(0) var samp: sampler;
|
|
4718
|
+
@group(2) @binding(1) var texture: texture_2d<f32>;
|
|
4719
|
+
|
|
4674
4720
|
@vertex
|
|
4675
|
-
fn vertexMain(
|
|
4676
|
-
var vert = vec4f(pos, 0.0, 1.0);
|
|
4677
|
-
vert = transforms[i32(
|
|
4721
|
+
fn vertexMain(input: VertexInput) -> VertexOutput {
|
|
4722
|
+
var vert = vec4f(input.pos, 0.0, 1.0);
|
|
4723
|
+
vert = transforms[i32(input.matrixIndex)] * vert;
|
|
4678
4724
|
vert.x /= uniforms.halfWidth;
|
|
4679
4725
|
vert.y /= uniforms.halfHeight;
|
|
4680
4726
|
|
|
4681
4727
|
var output: VertexOutput;
|
|
4682
4728
|
output.position = vert;
|
|
4683
|
-
output.texCoord = texCoord;
|
|
4729
|
+
output.texCoord = input.texCoord;
|
|
4730
|
+
output.tintIndex = input.tintIndex;
|
|
4684
4731
|
return output;
|
|
4685
4732
|
}
|
|
4686
|
-
`
|
|
4687
|
-
});
|
|
4688
|
-
|
|
4689
|
-
let fragmentShader = Q5.device.createShaderModule({
|
|
4690
|
-
label: 'imageFragmentShader',
|
|
4691
|
-
code: `
|
|
4692
|
-
@group(2) @binding(0) var samp: sampler;
|
|
4693
|
-
@group(2) @binding(1) var texture: texture_2d<f32>;
|
|
4694
4733
|
|
|
4695
4734
|
@fragment
|
|
4696
|
-
fn fragmentMain(@location(0) texCoord: vec2f) -> @location(0) vec4f {
|
|
4697
|
-
|
|
4698
|
-
|
|
4735
|
+
fn fragmentMain(@location(0) texCoord: vec2f, @location(1) tintIndex: f32) -> @location(0) vec4f {
|
|
4736
|
+
let texColor = textureSample(texture, samp, texCoord);
|
|
4737
|
+
let tintColor = colors[i32(tintIndex)];
|
|
4738
|
+
|
|
4739
|
+
// Mix original and tinted colors using tint alpha as blend factor
|
|
4740
|
+
let tinted = vec4f(texColor.rgb * tintColor.rgb, texColor.a);
|
|
4741
|
+
return mix(texColor, tinted, tintColor.a);
|
|
4699
4742
|
}
|
|
4700
4743
|
`
|
|
4701
4744
|
});
|
|
@@ -4717,11 +4760,12 @@ fn fragmentMain(@location(0) texCoord: vec2f) -> @location(0) vec4f {
|
|
|
4717
4760
|
});
|
|
4718
4761
|
|
|
4719
4762
|
const vertexBufferLayout = {
|
|
4720
|
-
arrayStride:
|
|
4763
|
+
arrayStride: 24,
|
|
4721
4764
|
attributes: [
|
|
4722
4765
|
{ shaderLocation: 0, offset: 0, format: 'float32x2' },
|
|
4723
4766
|
{ shaderLocation: 1, offset: 8, format: 'float32x2' },
|
|
4724
|
-
{ shaderLocation: 2, offset: 16, format: 'float32' } //
|
|
4767
|
+
{ shaderLocation: 2, offset: 16, format: 'float32' }, // tintIndex
|
|
4768
|
+
{ shaderLocation: 3, offset: 20, format: 'float32' } // matrixIndex
|
|
4725
4769
|
]
|
|
4726
4770
|
};
|
|
4727
4771
|
|
|
@@ -4734,12 +4778,12 @@ fn fragmentMain(@location(0) texCoord: vec2f) -> @location(0) vec4f {
|
|
|
4734
4778
|
label: 'imagePipeline',
|
|
4735
4779
|
layout: pipelineLayout,
|
|
4736
4780
|
vertex: {
|
|
4737
|
-
module:
|
|
4781
|
+
module: imageShader,
|
|
4738
4782
|
entryPoint: 'vertexMain',
|
|
4739
4783
|
buffers: [{ arrayStride: 0, attributes: [] }, vertexBufferLayout]
|
|
4740
4784
|
},
|
|
4741
4785
|
fragment: {
|
|
4742
|
-
module:
|
|
4786
|
+
module: imageShader,
|
|
4743
4787
|
entryPoint: 'fragmentMain',
|
|
4744
4788
|
targets: [{ format: 'bgra8unorm', blend: $.blendConfigs.normal }]
|
|
4745
4789
|
},
|
|
@@ -4815,58 +4859,63 @@ fn fragmentMain(@location(0) texCoord: vec2f) -> @location(0) vec4f {
|
|
|
4815
4859
|
|
|
4816
4860
|
$.loadImage = (src, cb) => {
|
|
4817
4861
|
q._preloadCount++;
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
// calculate the default width and height that the image
|
|
4822
|
-
// should be drawn at if the user doesn't specify a display size
|
|
4823
|
-
img.defaultWidth = img.width * $._defaultImageScale;
|
|
4824
|
-
img.defaultHeight = img.height * $._defaultImageScale;
|
|
4825
|
-
img.pixelDensity = 1;
|
|
4826
|
-
|
|
4862
|
+
let g = $._g.loadImage(src, (img) => {
|
|
4863
|
+
g.defaultWidth = img.width * $._defaultImageScale;
|
|
4864
|
+
g.defaultHeight = img.height * $._defaultImageScale;
|
|
4827
4865
|
$._createTexture(img);
|
|
4828
4866
|
q._preloadCount--;
|
|
4829
4867
|
if (cb) cb(img);
|
|
4830
|
-
};
|
|
4831
|
-
|
|
4832
|
-
return img;
|
|
4868
|
+
});
|
|
4869
|
+
return g;
|
|
4833
4870
|
};
|
|
4834
4871
|
|
|
4835
4872
|
$.imageMode = (x) => ($._imageMode = x);
|
|
4836
4873
|
|
|
4837
|
-
|
|
4874
|
+
const addVert = (x, y, u, v, ci, ti) => {
|
|
4875
|
+
let s = vertexStack,
|
|
4876
|
+
i = vertIndex;
|
|
4877
|
+
s[i++] = x;
|
|
4878
|
+
s[i++] = y;
|
|
4879
|
+
s[i++] = u;
|
|
4880
|
+
s[i++] = v;
|
|
4881
|
+
s[i++] = ci;
|
|
4882
|
+
s[i++] = ti;
|
|
4883
|
+
vertIndex = i;
|
|
4884
|
+
};
|
|
4885
|
+
|
|
4886
|
+
$.image = (img, dx = 0, dy = 0, dw, dh, sx = 0, sy = 0, sw, sh) => {
|
|
4887
|
+
let g = img;
|
|
4838
4888
|
if (img.canvas) img = img.canvas;
|
|
4839
4889
|
if (img.textureIndex == undefined) return;
|
|
4840
4890
|
|
|
4841
4891
|
if ($._matrixDirty) $._saveMatrix();
|
|
4842
|
-
let ti = $._transformIndex;
|
|
4843
4892
|
|
|
4844
|
-
let
|
|
4845
|
-
|
|
4893
|
+
let ti = $._matrixIndex,
|
|
4894
|
+
w = img.width,
|
|
4895
|
+
h = img.height;
|
|
4846
4896
|
|
|
4847
|
-
dw ??=
|
|
4848
|
-
dh ??=
|
|
4897
|
+
dw ??= g.defaultWidth;
|
|
4898
|
+
dh ??= g.defaultHeight;
|
|
4849
4899
|
sw ??= w;
|
|
4850
4900
|
sh ??= h;
|
|
4851
4901
|
|
|
4852
|
-
let pd =
|
|
4902
|
+
let pd = g._pixelDensity || 1;
|
|
4853
4903
|
dw *= pd;
|
|
4854
4904
|
dh *= pd;
|
|
4855
4905
|
|
|
4856
4906
|
let [l, r, t, b] = $._calcBox(dx, dy, dw, dh, $._imageMode);
|
|
4857
4907
|
|
|
4858
|
-
let u0 = sx / w
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
);
|
|
4908
|
+
let u0 = sx / w,
|
|
4909
|
+
v0 = sy / h,
|
|
4910
|
+
u1 = (sx + sw) / w,
|
|
4911
|
+
v1 = (sy + sh) / h;
|
|
4912
|
+
|
|
4913
|
+
let ci = $._tint;
|
|
4914
|
+
|
|
4915
|
+
addVert(l, t, u0, v0, ci, ti);
|
|
4916
|
+
addVert(r, t, u1, v0, ci, ti);
|
|
4917
|
+
addVert(l, b, u0, v1, ci, ti);
|
|
4918
|
+
addVert(r, b, u1, v1, ci, ti);
|
|
4870
4919
|
|
|
4871
4920
|
$.drawStack.push(1, img.textureIndex);
|
|
4872
4921
|
};
|
|
@@ -4877,20 +4926,20 @@ fn fragmentMain(@location(0) texCoord: vec2f) -> @location(0) vec4f {
|
|
|
4877
4926
|
// Switch to image pipeline
|
|
4878
4927
|
$.pass.setPipeline($._pipelines[1]);
|
|
4879
4928
|
|
|
4880
|
-
|
|
4881
|
-
size:
|
|
4929
|
+
let vertexBuffer = Q5.device.createBuffer({
|
|
4930
|
+
size: vertIndex * 4,
|
|
4882
4931
|
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
|
|
4883
4932
|
mappedAtCreation: true
|
|
4884
4933
|
});
|
|
4885
4934
|
|
|
4886
|
-
new Float32Array(vertexBuffer.getMappedRange()).set(vertexStack);
|
|
4935
|
+
new Float32Array(vertexBuffer.getMappedRange()).set(vertexStack.slice(0, vertIndex));
|
|
4887
4936
|
vertexBuffer.unmap();
|
|
4888
4937
|
|
|
4889
4938
|
$.pass.setVertexBuffer(1, vertexBuffer);
|
|
4890
4939
|
});
|
|
4891
4940
|
|
|
4892
4941
|
$._hooks.postRender.push(() => {
|
|
4893
|
-
|
|
4942
|
+
vertIndex = 0;
|
|
4894
4943
|
});
|
|
4895
4944
|
};
|
|
4896
4945
|
|
|
@@ -4927,7 +4976,7 @@ struct Char {
|
|
|
4927
4976
|
struct Text {
|
|
4928
4977
|
pos: vec2f,
|
|
4929
4978
|
scale: f32,
|
|
4930
|
-
|
|
4979
|
+
matrixIndex: f32,
|
|
4931
4980
|
fillIndex: f32,
|
|
4932
4981
|
strokeIndex: f32
|
|
4933
4982
|
}
|
|
@@ -4959,7 +5008,7 @@ fn vertexMain(input : VertexInput) -> VertexOutput {
|
|
|
4959
5008
|
let charPos = ((pos[input.vertex] * fontChar.size + char.xy + fontChar.offset) * text.scale) + text.pos;
|
|
4960
5009
|
|
|
4961
5010
|
var vert = vec4f(charPos, 0.0, 1.0);
|
|
4962
|
-
vert = transforms[i32(text.
|
|
5011
|
+
vert = transforms[i32(text.matrixIndex)] * vert;
|
|
4963
5012
|
vert.x /= uniforms.halfWidth;
|
|
4964
5013
|
vert.y /= uniforms.halfHeight;
|
|
4965
5014
|
|
|
@@ -5183,13 +5232,11 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
|
|
|
5183
5232
|
if (cb) cb(fontName);
|
|
5184
5233
|
};
|
|
5185
5234
|
|
|
5186
|
-
|
|
5187
|
-
let g = $.createGraphics(1, 1);
|
|
5188
|
-
g.colorMode($.RGB, 1);
|
|
5235
|
+
$._g.colorMode($.RGB, 1);
|
|
5189
5236
|
|
|
5190
5237
|
$.loadFont = (url, cb) => {
|
|
5191
5238
|
let ext = url.slice(url.lastIndexOf('.') + 1);
|
|
5192
|
-
if (ext != 'json') return
|
|
5239
|
+
if (ext != 'json') return $._g.loadFont(url, cb);
|
|
5193
5240
|
let fontName = url.slice(url.lastIndexOf('/') + 1, url.lastIndexOf('-'));
|
|
5194
5241
|
createFont(url, fontName, cb);
|
|
5195
5242
|
return fontName;
|
|
@@ -5374,7 +5421,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
|
|
|
5374
5421
|
text[0] = x;
|
|
5375
5422
|
text[1] = -y;
|
|
5376
5423
|
text[2] = $._textSize / 44;
|
|
5377
|
-
text[3] = $.
|
|
5424
|
+
text[3] = $._matrixIndex;
|
|
5378
5425
|
text[4] = $._fillSet ? $._fill : 0;
|
|
5379
5426
|
text[5] = $._stroke;
|
|
5380
5427
|
|
|
@@ -5388,18 +5435,18 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
|
|
|
5388
5435
|
};
|
|
5389
5436
|
|
|
5390
5437
|
$.createTextImage = (str, w, h) => {
|
|
5391
|
-
|
|
5438
|
+
$._g.textSize($._textSize);
|
|
5392
5439
|
|
|
5393
5440
|
if ($._doFill) {
|
|
5394
5441
|
let fi = $._fill * 4;
|
|
5395
|
-
|
|
5442
|
+
$._g.fill(colorStack.slice(fi, fi + 4));
|
|
5396
5443
|
}
|
|
5397
5444
|
if ($._doStroke) {
|
|
5398
5445
|
let si = $._stroke * 4;
|
|
5399
|
-
|
|
5446
|
+
$._g.stroke(colorStack.slice(si, si + 4));
|
|
5400
5447
|
}
|
|
5401
5448
|
|
|
5402
|
-
let img =
|
|
5449
|
+
let img = $._g.createTextImage(str, w, h);
|
|
5403
5450
|
|
|
5404
5451
|
if (img.canvas.textureIndex == undefined) {
|
|
5405
5452
|
$._createTexture(img);
|