q5 2.20.5 → 2.20.7
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 -6
- package/q5.js +205 -120
- package/q5.min.js +1 -1
package/q5.js
CHANGED
|
@@ -29,6 +29,7 @@ function Q5(scope, parent, renderer) {
|
|
|
29
29
|
Q5._hasGlobal = $._isGlobal = true;
|
|
30
30
|
globalScope = Q5._esm ? globalThis : !Q5._server ? window : global;
|
|
31
31
|
}
|
|
32
|
+
if (scope == 'graphics') $._graphics = true;
|
|
32
33
|
|
|
33
34
|
let q = new Proxy($, {
|
|
34
35
|
set: (t, p, v) => {
|
|
@@ -171,18 +172,15 @@ function Q5(scope, parent, renderer) {
|
|
|
171
172
|
}
|
|
172
173
|
}
|
|
173
174
|
|
|
174
|
-
if (
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
175
|
+
if ($._webgpuFallback) $.colorMode('rgb', 1);
|
|
176
|
+
|
|
177
|
+
if ($._graphics) return;
|
|
178
178
|
|
|
179
179
|
if (scope == 'global') {
|
|
180
180
|
Object.assign(Q5, $);
|
|
181
181
|
delete Q5.Q5;
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
if ($._webgpuFallback) $.colorMode('rgb', 1);
|
|
185
|
-
|
|
186
184
|
for (let m of Q5.methods.init) {
|
|
187
185
|
m.call($);
|
|
188
186
|
}
|
|
@@ -324,7 +322,7 @@ if (typeof document == 'object') {
|
|
|
324
322
|
});
|
|
325
323
|
}
|
|
326
324
|
Q5.modules.canvas = ($, q) => {
|
|
327
|
-
$.
|
|
325
|
+
$._Canvas =
|
|
328
326
|
window.OffscreenCanvas ||
|
|
329
327
|
function () {
|
|
330
328
|
return document.createElement('canvas');
|
|
@@ -335,7 +333,7 @@ Q5.modules.canvas = ($, q) => {
|
|
|
335
333
|
q.canvas = Q5._createServerCanvas(100, 100);
|
|
336
334
|
}
|
|
337
335
|
} else if ($._scope == 'image' || $._scope == 'graphics') {
|
|
338
|
-
q.canvas = new $.
|
|
336
|
+
q.canvas = new $._Canvas(100, 100);
|
|
339
337
|
}
|
|
340
338
|
|
|
341
339
|
if (!$.canvas) {
|
|
@@ -411,12 +409,13 @@ Q5.modules.canvas = ($, q) => {
|
|
|
411
409
|
}
|
|
412
410
|
if ($._beginRender) $._beginRender();
|
|
413
411
|
|
|
412
|
+
c.mousePressed = (cb) => c.addEventListener('mousedown', cb);
|
|
413
|
+
|
|
414
414
|
return rend;
|
|
415
415
|
};
|
|
416
416
|
|
|
417
|
-
$.createGraphics = function (w, h, opt) {
|
|
418
|
-
let g = new Q5('graphics');
|
|
419
|
-
opt ??= {};
|
|
417
|
+
$.createGraphics = function (w, h, opt = {}) {
|
|
418
|
+
let g = new Q5('graphics', undefined, opt.renderer || ($._webgpuFallback ? 'webgpu-fallback' : $._renderer));
|
|
420
419
|
opt.alpha ??= true;
|
|
421
420
|
opt.colorSpace ??= $.canvas.colorSpace;
|
|
422
421
|
g.createCanvas.call($, w, h, opt);
|
|
@@ -698,7 +697,7 @@ Q5.renderers.c2d.canvas = ($, q) => {
|
|
|
698
697
|
|
|
699
698
|
let o;
|
|
700
699
|
if ($.frameCount > 1) {
|
|
701
|
-
o = new $.
|
|
700
|
+
o = new $._Canvas(c.width, c.height);
|
|
702
701
|
o.w = c.w;
|
|
703
702
|
o.h = c.h;
|
|
704
703
|
let oCtx = o.getContext('2d');
|
|
@@ -1443,7 +1442,7 @@ Q5.renderers.c2d.image = ($, q) => {
|
|
|
1443
1442
|
if ($._scope == 'image') {
|
|
1444
1443
|
$.resize = (w, h) => {
|
|
1445
1444
|
let c = $.canvas;
|
|
1446
|
-
let o = new $.
|
|
1445
|
+
let o = new $._Canvas(c.width, c.height);
|
|
1447
1446
|
let tmpCtx = o.getContext('2d', {
|
|
1448
1447
|
colorSpace: c.colorSpace
|
|
1449
1448
|
});
|
|
@@ -1581,7 +1580,7 @@ Q5.renderers.c2d.image = ($, q) => {
|
|
|
1581
1580
|
|
|
1582
1581
|
$._saveCanvas = async (data, ext) => {
|
|
1583
1582
|
data = data.canvas || data;
|
|
1584
|
-
if (data instanceof OffscreenCanvas) {
|
|
1583
|
+
if (data instanceof HTMLCanvasElement || data instanceof OffscreenCanvas) {
|
|
1585
1584
|
const blob = await data.convertToBlob({ type: 'image/' + ext });
|
|
1586
1585
|
|
|
1587
1586
|
return await new Promise((resolve) => {
|
|
@@ -2610,6 +2609,8 @@ Q5.modules.dom = ($, q) => {
|
|
|
2610
2609
|
return el;
|
|
2611
2610
|
};
|
|
2612
2611
|
|
|
2612
|
+
el.mousePressed = (cb) => el.addEventListener('mousedown', cb);
|
|
2613
|
+
|
|
2613
2614
|
$._elements.push(el);
|
|
2614
2615
|
if ($.canvas) $.canvas.parentElement.append(el);
|
|
2615
2616
|
else document.body.append(el);
|
|
@@ -4469,15 +4470,14 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
4469
4470
|
c.width = $.width = 500;
|
|
4470
4471
|
c.height = $.height = 500;
|
|
4471
4472
|
|
|
4472
|
-
|
|
4473
|
-
$._g = $.createGraphics(1, 1);
|
|
4473
|
+
$._g = $.createGraphics(1, 1, { renderer: 'c2d' });
|
|
4474
4474
|
|
|
4475
4475
|
if ($.colorMode) $.colorMode('rgb', 1);
|
|
4476
4476
|
|
|
4477
4477
|
let pass,
|
|
4478
4478
|
mainView,
|
|
4479
|
-
|
|
4480
|
-
|
|
4479
|
+
frameA,
|
|
4480
|
+
frameB,
|
|
4481
4481
|
frameSampler,
|
|
4482
4482
|
framePipeline,
|
|
4483
4483
|
frameBindGroup,
|
|
@@ -4486,6 +4486,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
4486
4486
|
|
|
4487
4487
|
$._pipelineConfigs = [];
|
|
4488
4488
|
$._pipelines = [];
|
|
4489
|
+
$._buffers = [];
|
|
4489
4490
|
|
|
4490
4491
|
// local variables used for slightly better performance
|
|
4491
4492
|
// stores pipeline shifts and vertex counts/image indices
|
|
@@ -4549,8 +4550,8 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
4549
4550
|
GPUTextureUsage.TEXTURE_BINDING |
|
|
4550
4551
|
GPUTextureUsage.RENDER_ATTACHMENT;
|
|
4551
4552
|
|
|
4552
|
-
|
|
4553
|
-
|
|
4553
|
+
$._frameA = frameA = Q5.device.createTexture({ size, format, usage });
|
|
4554
|
+
$._frameB = frameB = Q5.device.createTexture({ size, format, usage });
|
|
4554
4555
|
|
|
4555
4556
|
let finalShader = Q5.device.createShaderModule({
|
|
4556
4557
|
code: `
|
|
@@ -4673,7 +4674,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
4673
4674
|
$._hsw = v / 2;
|
|
4674
4675
|
};
|
|
4675
4676
|
|
|
4676
|
-
const MAX_TRANSFORMS =
|
|
4677
|
+
const MAX_TRANSFORMS = $._graphics ? 1000 : 1e7,
|
|
4677
4678
|
MATRIX_SIZE = 16, // 4x4 matrix
|
|
4678
4679
|
transforms = new Float32Array(MAX_TRANSFORMS * MATRIX_SIZE);
|
|
4679
4680
|
|
|
@@ -4953,8 +4954,6 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
4953
4954
|
shouldClear = true;
|
|
4954
4955
|
};
|
|
4955
4956
|
|
|
4956
|
-
$.createGraphics = (w, h, opt) => $._g.createGraphics(w, h, opt);
|
|
4957
|
-
|
|
4958
4957
|
const _drawFrame = () => {
|
|
4959
4958
|
pass.setPipeline(framePipeline);
|
|
4960
4959
|
pass.setBindGroup(0, frameBindGroup);
|
|
@@ -4963,14 +4962,13 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
4963
4962
|
|
|
4964
4963
|
$._beginRender = () => {
|
|
4965
4964
|
// swap the frame textures
|
|
4966
|
-
const temp =
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
$.canvas.texture = frameTextureA;
|
|
4965
|
+
const temp = frameA;
|
|
4966
|
+
frameA = frameB;
|
|
4967
|
+
frameB = temp;
|
|
4970
4968
|
|
|
4971
4969
|
$.encoder = Q5.device.createCommandEncoder();
|
|
4972
4970
|
|
|
4973
|
-
let target = shouldClear ? $.ctx.getCurrentTexture().createView() :
|
|
4971
|
+
let target = shouldClear ? $.ctx.getCurrentTexture().createView() : frameA.createView();
|
|
4974
4972
|
|
|
4975
4973
|
pass = q.pass = $.encoder.beginRenderPass({
|
|
4976
4974
|
label: 'q5-webgpu',
|
|
@@ -4990,7 +4988,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
4990
4988
|
layout: framePipeline.getBindGroupLayout(0),
|
|
4991
4989
|
entries: [
|
|
4992
4990
|
{ binding: 0, resource: frameSampler },
|
|
4993
|
-
{ binding: 1, resource:
|
|
4991
|
+
{ binding: 1, resource: frameB.createView() }
|
|
4994
4992
|
]
|
|
4995
4993
|
});
|
|
4996
4994
|
|
|
@@ -5048,7 +5046,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
5048
5046
|
// v is the number of vertices
|
|
5049
5047
|
pass.draw(v, 1, drawVertOffset);
|
|
5050
5048
|
drawVertOffset += v;
|
|
5051
|
-
} else if (curPipelineIndex
|
|
5049
|
+
} else if (curPipelineIndex <= 2) {
|
|
5052
5050
|
// draw an image or video frame
|
|
5053
5051
|
// v is the texture index
|
|
5054
5052
|
pass.setBindGroup(1, $._textureBindGroups[v]);
|
|
@@ -5088,7 +5086,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
5088
5086
|
layout: framePipeline.getBindGroupLayout(0),
|
|
5089
5087
|
entries: [
|
|
5090
5088
|
{ binding: 0, resource: frameSampler },
|
|
5091
|
-
{ binding: 1, resource:
|
|
5089
|
+
{ binding: 1, resource: frameA.createView() }
|
|
5092
5090
|
]
|
|
5093
5091
|
});
|
|
5094
5092
|
_drawFrame();
|
|
@@ -5098,6 +5096,12 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
5098
5096
|
|
|
5099
5097
|
Q5.device.queue.submit([$.encoder.finish()]);
|
|
5100
5098
|
|
|
5099
|
+
// destroy buffers
|
|
5100
|
+
Q5.device.queue.onSubmittedWorkDone().then(() => {
|
|
5101
|
+
for (let b of $._buffers) b.destroy();
|
|
5102
|
+
$._buffers = [];
|
|
5103
|
+
});
|
|
5104
|
+
|
|
5101
5105
|
q.pass = $.encoder = null;
|
|
5102
5106
|
|
|
5103
5107
|
// clear the stacks for the next frame
|
|
@@ -5123,6 +5127,11 @@ Q5.initWebGPU = async () => {
|
|
|
5123
5127
|
return false;
|
|
5124
5128
|
}
|
|
5125
5129
|
Q5.device = await adapter.requestDevice();
|
|
5130
|
+
|
|
5131
|
+
Q5.device.lost.then((e) => {
|
|
5132
|
+
console.error('WebGPU crashed!');
|
|
5133
|
+
console.error(e);
|
|
5134
|
+
});
|
|
5126
5135
|
}
|
|
5127
5136
|
return true;
|
|
5128
5137
|
};
|
|
@@ -5137,14 +5146,12 @@ Q5.webgpu = async function (scope, parent) {
|
|
|
5137
5146
|
Q5.renderers.webgpu.drawing = ($, q) => {
|
|
5138
5147
|
let c = $.canvas,
|
|
5139
5148
|
drawStack = $.drawStack,
|
|
5140
|
-
vertexStack = new Float32Array(1e7),
|
|
5149
|
+
vertexStack = new Float32Array($._graphics ? 1000 : 1e7),
|
|
5141
5150
|
vertIndex = 0;
|
|
5142
5151
|
const TAU = Math.PI * 2;
|
|
5143
5152
|
const HALF_PI = Math.PI / 2;
|
|
5144
5153
|
|
|
5145
|
-
let
|
|
5146
|
-
label: 'drawingShader',
|
|
5147
|
-
code: `
|
|
5154
|
+
let drawingShaderCode = `
|
|
5148
5155
|
struct Uniforms {
|
|
5149
5156
|
halfWidth: f32,
|
|
5150
5157
|
halfHeight: f32
|
|
@@ -5163,12 +5170,17 @@ struct FragmentParams {
|
|
|
5163
5170
|
@group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;
|
|
5164
5171
|
@group(0) @binding(2) var<storage> colors : array<vec4f>;
|
|
5165
5172
|
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
vert = transforms[i32(v.matrixIndex)] * vert;
|
|
5173
|
+
fn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {
|
|
5174
|
+
var vert = vec4f(pos, 0.0, 1.0);
|
|
5175
|
+
vert = transforms[i32(matrixIndex)] * vert;
|
|
5170
5176
|
vert.x /= uniforms.halfWidth;
|
|
5171
5177
|
vert.y /= uniforms.halfHeight;
|
|
5178
|
+
return vert;
|
|
5179
|
+
}
|
|
5180
|
+
|
|
5181
|
+
@vertex
|
|
5182
|
+
fn vertexMain(v: VertexParams) -> FragmentParams {
|
|
5183
|
+
var vert = transformVertex(v.pos, v.matrixIndex);
|
|
5172
5184
|
|
|
5173
5185
|
var f: FragmentParams;
|
|
5174
5186
|
f.position = vert;
|
|
@@ -5177,10 +5189,14 @@ fn vertexMain(v: VertexParams) -> FragmentParams {
|
|
|
5177
5189
|
}
|
|
5178
5190
|
|
|
5179
5191
|
@fragment
|
|
5180
|
-
fn fragmentMain(
|
|
5181
|
-
return color;
|
|
5192
|
+
fn fragmentMain(f: FragmentParams) -> @location(0) vec4f {
|
|
5193
|
+
return f.color;
|
|
5182
5194
|
}
|
|
5183
|
-
|
|
5195
|
+
`;
|
|
5196
|
+
|
|
5197
|
+
let drawingShader = Q5.device.createShaderModule({
|
|
5198
|
+
label: 'drawingShader',
|
|
5199
|
+
code: drawingShaderCode
|
|
5184
5200
|
});
|
|
5185
5201
|
|
|
5186
5202
|
let vertexBufferLayout = {
|
|
@@ -5758,6 +5774,8 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
5758
5774
|
vertexBuffer.unmap();
|
|
5759
5775
|
|
|
5760
5776
|
$.pass.setVertexBuffer(0, vertexBuffer);
|
|
5777
|
+
|
|
5778
|
+
$._buffers.push(vertexBuffer);
|
|
5761
5779
|
});
|
|
5762
5780
|
|
|
5763
5781
|
$._hooks.postRender.push(() => {
|
|
@@ -5766,7 +5784,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
5766
5784
|
});
|
|
5767
5785
|
};
|
|
5768
5786
|
Q5.renderers.webgpu.image = ($, q) => {
|
|
5769
|
-
let vertexStack = new Float32Array(1e7),
|
|
5787
|
+
let vertexStack = new Float32Array($._graphics ? 1000 : 1e7),
|
|
5770
5788
|
vertIndex = 0;
|
|
5771
5789
|
|
|
5772
5790
|
let imageShaderCode = `
|
|
@@ -5779,13 +5797,13 @@ struct VertexParams {
|
|
|
5779
5797
|
@location(1) texCoord: vec2f,
|
|
5780
5798
|
@location(2) tintIndex: f32,
|
|
5781
5799
|
@location(3) matrixIndex: f32,
|
|
5782
|
-
@location(4)
|
|
5800
|
+
@location(4) imageAlpha: f32
|
|
5783
5801
|
}
|
|
5784
5802
|
struct FragmentParams {
|
|
5785
5803
|
@builtin(position) position: vec4f,
|
|
5786
5804
|
@location(0) texCoord: vec2f,
|
|
5787
|
-
@location(1)
|
|
5788
|
-
@location(2)
|
|
5805
|
+
@location(1) tintColor: vec4f,
|
|
5806
|
+
@location(2) imageAlpha: f32
|
|
5789
5807
|
}
|
|
5790
5808
|
|
|
5791
5809
|
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
|
@@ -5795,29 +5813,33 @@ struct FragmentParams {
|
|
|
5795
5813
|
@group(1) @binding(0) var samp: sampler;
|
|
5796
5814
|
@group(1) @binding(1) var texture: texture_2d<f32>;
|
|
5797
5815
|
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
vert = transforms[i32(v.matrixIndex)] * vert;
|
|
5816
|
+
fn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {
|
|
5817
|
+
var vert = vec4f(pos, 0.0, 1.0);
|
|
5818
|
+
vert = transforms[i32(matrixIndex)] * vert;
|
|
5802
5819
|
vert.x /= uniforms.halfWidth;
|
|
5803
5820
|
vert.y /= uniforms.halfHeight;
|
|
5821
|
+
return vert;
|
|
5822
|
+
}
|
|
5823
|
+
|
|
5824
|
+
@vertex
|
|
5825
|
+
fn vertexMain(v: VertexParams) -> FragmentParams {
|
|
5826
|
+
var vert = transformVertex(v.pos, v.matrixIndex);
|
|
5804
5827
|
|
|
5805
5828
|
var f: FragmentParams;
|
|
5806
5829
|
f.position = vert;
|
|
5807
5830
|
f.texCoord = v.texCoord;
|
|
5808
|
-
f.
|
|
5809
|
-
f.
|
|
5831
|
+
f.tintColor = colors[i32(v.tintIndex)];
|
|
5832
|
+
f.imageAlpha = v.imageAlpha;
|
|
5810
5833
|
return f;
|
|
5811
5834
|
}
|
|
5812
5835
|
|
|
5813
5836
|
@fragment
|
|
5814
5837
|
fn fragmentMain(f: FragmentParams) -> @location(0) vec4f {
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
return mix(texColor, tinted, tintColor.a);
|
|
5838
|
+
let texColor = textureSample(texture, samp, f.texCoord);
|
|
5839
|
+
|
|
5840
|
+
// Mix original and tinted colors using tint alpha as blend factor
|
|
5841
|
+
let tinted = vec4f(texColor.rgb * f.tintColor.rgb, texColor.a * f.imageAlpha);
|
|
5842
|
+
return mix(texColor, tinted, f.tintColor.a);
|
|
5821
5843
|
}
|
|
5822
5844
|
`;
|
|
5823
5845
|
|
|
@@ -5842,7 +5864,7 @@ fn fragmentMain(f: FragmentParams) -> @location(0) vec4f {
|
|
|
5842
5864
|
{ shaderLocation: 1, offset: 8, format: 'float32x2' },
|
|
5843
5865
|
{ shaderLocation: 2, offset: 16, format: 'float32' }, // tintIndex
|
|
5844
5866
|
{ shaderLocation: 3, offset: 20, format: 'float32' }, // matrixIndex
|
|
5845
|
-
{ shaderLocation: 4, offset: 24, format: 'float32' } //
|
|
5867
|
+
{ shaderLocation: 4, offset: 24, format: 'float32' } // imageAlpha
|
|
5846
5868
|
]
|
|
5847
5869
|
};
|
|
5848
5870
|
|
|
@@ -5943,29 +5965,30 @@ fn fragmentMain(f: FragmentParams) -> @location(0) vec4f {
|
|
|
5943
5965
|
let tIdx = 0,
|
|
5944
5966
|
vidFrames = 0;
|
|
5945
5967
|
|
|
5946
|
-
$.
|
|
5947
|
-
let
|
|
5948
|
-
if (img.canvas) img = img.canvas;
|
|
5968
|
+
$._addTexture = (img, texture) => {
|
|
5969
|
+
let cnv = img.canvas || img;
|
|
5949
5970
|
|
|
5950
|
-
let textureSize = [
|
|
5971
|
+
let textureSize = [cnv.width, cnv.height, 1];
|
|
5951
5972
|
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5973
|
+
if (!texture) {
|
|
5974
|
+
texture = Q5.device.createTexture({
|
|
5975
|
+
size: textureSize,
|
|
5976
|
+
format: 'bgra8unorm',
|
|
5977
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT
|
|
5978
|
+
});
|
|
5957
5979
|
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5980
|
+
Q5.device.queue.copyExternalImageToTexture(
|
|
5981
|
+
{ source: cnv },
|
|
5982
|
+
{
|
|
5983
|
+
texture,
|
|
5984
|
+
colorSpace: $.canvas.colorSpace
|
|
5985
|
+
},
|
|
5986
|
+
textureSize
|
|
5987
|
+
);
|
|
5988
|
+
}
|
|
5966
5989
|
|
|
5967
|
-
|
|
5968
|
-
|
|
5990
|
+
img.texture = texture;
|
|
5991
|
+
img.textureIndex = tIdx + vidFrames;
|
|
5969
5992
|
|
|
5970
5993
|
$._textureBindGroups[tIdx + vidFrames] = Q5.device.createBindGroup({
|
|
5971
5994
|
layout: textureLayout,
|
|
@@ -5978,21 +6001,41 @@ fn fragmentMain(f: FragmentParams) -> @location(0) vec4f {
|
|
|
5978
6001
|
tIdx++;
|
|
5979
6002
|
};
|
|
5980
6003
|
|
|
6004
|
+
let Q5Image = Q5.Image;
|
|
6005
|
+
Q5.Image = function (w, h) {
|
|
6006
|
+
let g = new Q5Image(...arguments);
|
|
6007
|
+
if (w > 1 && h > 1) {
|
|
6008
|
+
$._addTexture(g);
|
|
6009
|
+
g.modified = true;
|
|
6010
|
+
}
|
|
6011
|
+
return g;
|
|
6012
|
+
};
|
|
6013
|
+
|
|
5981
6014
|
$.loadImage = (src, cb) => {
|
|
5982
6015
|
q._preloadCount++;
|
|
5983
6016
|
let g = $._g.loadImage(src, (img) => {
|
|
5984
|
-
|
|
5985
|
-
g.defaultHeight = img.height * $._defaultImageScale;
|
|
5986
|
-
$._createTexture(img);
|
|
6017
|
+
$._addTexture(img);
|
|
5987
6018
|
q._preloadCount--;
|
|
5988
6019
|
if (cb) cb(g);
|
|
5989
6020
|
});
|
|
5990
6021
|
return g;
|
|
5991
6022
|
};
|
|
5992
6023
|
|
|
6024
|
+
$.createImage = $._g.createImage;
|
|
6025
|
+
|
|
6026
|
+
let _createGraphics = $.createGraphics;
|
|
6027
|
+
|
|
6028
|
+
$.createGraphics = (w, h, opt) => {
|
|
6029
|
+
let g = _createGraphics(w, h, opt);
|
|
6030
|
+
$._addTexture(g, g._frameA);
|
|
6031
|
+
$._addTexture(g, g._frameB);
|
|
6032
|
+
g._beginRender();
|
|
6033
|
+
return g;
|
|
6034
|
+
};
|
|
6035
|
+
|
|
5993
6036
|
$.imageMode = (x) => ($._imageMode = x);
|
|
5994
6037
|
|
|
5995
|
-
const addVert = (x, y, u, v, ci, ti,
|
|
6038
|
+
const addVert = (x, y, u, v, ci, ti, ia) => {
|
|
5996
6039
|
let s = vertexStack,
|
|
5997
6040
|
i = vertIndex;
|
|
5998
6041
|
s[i++] = x;
|
|
@@ -6001,15 +6044,15 @@ fn fragmentMain(f: FragmentParams) -> @location(0) vec4f {
|
|
|
6001
6044
|
s[i++] = v;
|
|
6002
6045
|
s[i++] = ci;
|
|
6003
6046
|
s[i++] = ti;
|
|
6004
|
-
s[i++] =
|
|
6047
|
+
s[i++] = ia;
|
|
6005
6048
|
vertIndex = i;
|
|
6006
6049
|
};
|
|
6007
6050
|
|
|
6008
6051
|
$.image = (img, dx = 0, dy = 0, dw, dh, sx = 0, sy = 0, sw, sh) => {
|
|
6009
|
-
let
|
|
6052
|
+
let isVideo;
|
|
6010
6053
|
if (img.textureIndex == undefined) {
|
|
6011
|
-
|
|
6012
|
-
if (!
|
|
6054
|
+
isVideo = img.tagName == 'VIDEO';
|
|
6055
|
+
if (!isVideo || !img.width) return;
|
|
6013
6056
|
if (img.flipped) $.scale(-1, 1);
|
|
6014
6057
|
}
|
|
6015
6058
|
|
|
@@ -6021,7 +6064,19 @@ fn fragmentMain(f: FragmentParams) -> @location(0) vec4f {
|
|
|
6021
6064
|
h = cnv.height,
|
|
6022
6065
|
pd = img._pixelDensity || 1;
|
|
6023
6066
|
|
|
6024
|
-
if (
|
|
6067
|
+
if (img._graphics) {
|
|
6068
|
+
let g = img;
|
|
6069
|
+
if (g.drawStack.length) {
|
|
6070
|
+
g._render();
|
|
6071
|
+
g._finishRender();
|
|
6072
|
+
g.textureIndex += g.frameCount % 2 == 0 ? -1 : 1;
|
|
6073
|
+
g.resetMatrix();
|
|
6074
|
+
g._beginRender();
|
|
6075
|
+
g.frameCount++;
|
|
6076
|
+
}
|
|
6077
|
+
}
|
|
6078
|
+
|
|
6079
|
+
if (img.modified) {
|
|
6025
6080
|
Q5.device.queue.copyExternalImageToTexture(
|
|
6026
6081
|
{ source: cnv },
|
|
6027
6082
|
{ texture: img.texture, colorSpace: $.canvas.colorSpace },
|
|
@@ -6045,17 +6100,17 @@ fn fragmentMain(f: FragmentParams) -> @location(0) vec4f {
|
|
|
6045
6100
|
v1 = (sy + sh) / h,
|
|
6046
6101
|
ti = $._matrixIndex,
|
|
6047
6102
|
ci = $._tint,
|
|
6048
|
-
|
|
6103
|
+
ia = $._imageAlpha;
|
|
6049
6104
|
|
|
6050
|
-
addVert(l, t, u0, v0, ci, ti,
|
|
6051
|
-
addVert(r, t, u1, v0, ci, ti,
|
|
6052
|
-
addVert(l, b, u0, v1, ci, ti,
|
|
6053
|
-
addVert(r, b, u1, v1, ci, ti,
|
|
6105
|
+
addVert(l, t, u0, v0, ci, ti, ia);
|
|
6106
|
+
addVert(r, t, u1, v0, ci, ti, ia);
|
|
6107
|
+
addVert(l, b, u0, v1, ci, ti, ia);
|
|
6108
|
+
addVert(r, b, u1, v1, ci, ti, ia);
|
|
6054
6109
|
|
|
6055
|
-
if (!
|
|
6110
|
+
if (!isVideo) {
|
|
6056
6111
|
$.drawStack.push(1, img.textureIndex);
|
|
6057
6112
|
} else {
|
|
6058
|
-
// render
|
|
6113
|
+
// render video
|
|
6059
6114
|
let externalTexture = Q5.device.importExternalTexture({ source: img });
|
|
6060
6115
|
|
|
6061
6116
|
// Create bind group for the external texture that will
|
|
@@ -6087,6 +6142,8 @@ fn fragmentMain(f: FragmentParams) -> @location(0) vec4f {
|
|
|
6087
6142
|
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
|
|
6088
6143
|
});
|
|
6089
6144
|
|
|
6145
|
+
$._buffers.push(buffer);
|
|
6146
|
+
|
|
6090
6147
|
let en = Q5.device.createCommandEncoder();
|
|
6091
6148
|
|
|
6092
6149
|
en.copyTextureToBuffer({ texture }, { buffer, bytesPerRow, rowsPerImage: h }, { width: w, height: h });
|
|
@@ -6117,7 +6174,7 @@ fn fragmentMain(f: FragmentParams) -> @location(0) vec4f {
|
|
|
6117
6174
|
let colorSpace = $.canvas.colorSpace;
|
|
6118
6175
|
data = new Uint8ClampedArray(data.buffer);
|
|
6119
6176
|
data = new ImageData(data, w, h, { colorSpace });
|
|
6120
|
-
let cnv = new
|
|
6177
|
+
let cnv = new $._Canvas(w, h);
|
|
6121
6178
|
let ctx = cnv.getContext('2d', { colorSpace });
|
|
6122
6179
|
ctx.putImageData(data, 0, 0);
|
|
6123
6180
|
|
|
@@ -6147,6 +6204,8 @@ fn fragmentMain(f: FragmentParams) -> @location(0) vec4f {
|
|
|
6147
6204
|
|
|
6148
6205
|
$.pass.setVertexBuffer(1, vertexBuffer);
|
|
6149
6206
|
|
|
6207
|
+
$._buffers.push(vertexBuffer);
|
|
6208
|
+
|
|
6150
6209
|
if (vidFrames) {
|
|
6151
6210
|
// Switch to video pipeline
|
|
6152
6211
|
$.pass.setPipeline($._pipelines[3]);
|
|
@@ -6170,9 +6229,7 @@ Q5.DILATE = 6;
|
|
|
6170
6229
|
Q5.ERODE = 7;
|
|
6171
6230
|
Q5.BLUR = 8;
|
|
6172
6231
|
Q5.renderers.webgpu.text = ($, q) => {
|
|
6173
|
-
let
|
|
6174
|
-
label: 'MSDF text shader',
|
|
6175
|
-
code: `
|
|
6232
|
+
let textShaderCode = `
|
|
6176
6233
|
struct Uniforms {
|
|
6177
6234
|
halfWidth: f32,
|
|
6178
6235
|
halfHeight: f32
|
|
@@ -6184,7 +6241,9 @@ struct VertexParams {
|
|
|
6184
6241
|
struct FragmentParams {
|
|
6185
6242
|
@builtin(position) position : vec4f,
|
|
6186
6243
|
@location(0) texCoord : vec2f,
|
|
6187
|
-
@location(1) fillColor : vec4f
|
|
6244
|
+
@location(1) fillColor : vec4f,
|
|
6245
|
+
@location(2) strokeColor : vec4f,
|
|
6246
|
+
@location(3) strokeWeight : f32
|
|
6188
6247
|
}
|
|
6189
6248
|
struct Char {
|
|
6190
6249
|
texOffset: vec2f,
|
|
@@ -6197,7 +6256,8 @@ struct Text {
|
|
|
6197
6256
|
scale: f32,
|
|
6198
6257
|
matrixIndex: f32,
|
|
6199
6258
|
fillIndex: f32,
|
|
6200
|
-
strokeIndex: f32
|
|
6259
|
+
strokeIndex: f32,
|
|
6260
|
+
strokeWeight: f32
|
|
6201
6261
|
}
|
|
6202
6262
|
|
|
6203
6263
|
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
|
@@ -6213,52 +6273,73 @@ struct Text {
|
|
|
6213
6273
|
|
|
6214
6274
|
const quad = array(vec2f(0, -1), vec2f(1, -1), vec2f(0, 0), vec2f(1, 0));
|
|
6215
6275
|
|
|
6276
|
+
fn sampleMsdf(texCoord: vec2f) -> f32 {
|
|
6277
|
+
let c = textureSample(fontTexture, fontSampler, texCoord);
|
|
6278
|
+
return max(min(c.r, c.g), min(max(c.r, c.g), c.b));
|
|
6279
|
+
}
|
|
6280
|
+
|
|
6281
|
+
fn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {
|
|
6282
|
+
var vert = vec4f(pos, 0.0, 1.0);
|
|
6283
|
+
vert = transforms[i32(matrixIndex)] * vert;
|
|
6284
|
+
vert.x /= uniforms.halfWidth;
|
|
6285
|
+
vert.y /= uniforms.halfHeight;
|
|
6286
|
+
return vert;
|
|
6287
|
+
}
|
|
6288
|
+
|
|
6216
6289
|
@vertex
|
|
6217
6290
|
fn vertexMain(v : VertexParams) -> FragmentParams {
|
|
6218
6291
|
let char = textChars[v.instance];
|
|
6219
|
-
|
|
6220
6292
|
let text = textMetadata[i32(char.w)];
|
|
6221
|
-
|
|
6222
6293
|
let fontChar = fontChars[i32(char.z)];
|
|
6223
6294
|
|
|
6224
6295
|
let charPos = ((quad[v.vertex] * fontChar.size + char.xy + fontChar.offset) * text.scale) + text.pos;
|
|
6225
6296
|
|
|
6226
|
-
var vert =
|
|
6227
|
-
vert = transforms[i32(text.matrixIndex)] * vert;
|
|
6228
|
-
vert.x /= uniforms.halfWidth;
|
|
6229
|
-
vert.y /= uniforms.halfHeight;
|
|
6297
|
+
var vert = transformVertex(charPos, text.matrixIndex);
|
|
6230
6298
|
|
|
6231
6299
|
var f : FragmentParams;
|
|
6232
6300
|
f.position = vert;
|
|
6233
6301
|
f.texCoord = (quad[v.vertex] * vec2f(1, -1)) * fontChar.texExtent + fontChar.texOffset;
|
|
6234
6302
|
f.fillColor = colors[i32(text.fillIndex)];
|
|
6303
|
+
f.strokeColor = colors[i32(text.strokeIndex)];
|
|
6304
|
+
f.strokeWeight = text.strokeWeight;
|
|
6235
6305
|
return f;
|
|
6236
6306
|
}
|
|
6237
6307
|
|
|
6238
|
-
fn sampleMsdf(texCoord: vec2f) -> f32 {
|
|
6239
|
-
let c = textureSample(fontTexture, fontSampler, texCoord);
|
|
6240
|
-
return max(min(c.r, c.g), min(max(c.r, c.g), c.b));
|
|
6241
|
-
}
|
|
6242
|
-
|
|
6243
6308
|
@fragment
|
|
6244
6309
|
fn fragmentMain(f : FragmentParams) -> @location(0) vec4f {
|
|
6245
|
-
// pxRange (AKA distanceRange) comes from the msdfgen tool,
|
|
6246
|
-
// uses the default which is 4.
|
|
6247
6310
|
let pxRange = 4.0;
|
|
6248
6311
|
let sz = vec2f(textureDimensions(fontTexture, 0));
|
|
6249
|
-
let dx = sz.x*length(vec2f(dpdxFine(f.texCoord.x), dpdyFine(f.texCoord.x)));
|
|
6250
|
-
let dy = sz.y*length(vec2f(dpdxFine(f.texCoord.y), dpdyFine(f.texCoord.y)));
|
|
6312
|
+
let dx = sz.x * length(vec2f(dpdxFine(f.texCoord.x), dpdyFine(f.texCoord.x)));
|
|
6313
|
+
let dy = sz.y * length(vec2f(dpdxFine(f.texCoord.y), dpdyFine(f.texCoord.y)));
|
|
6251
6314
|
let toPixels = pxRange * inverseSqrt(dx * dx + dy * dy);
|
|
6252
6315
|
let sigDist = sampleMsdf(f.texCoord) - 0.5;
|
|
6253
6316
|
let pxDist = sigDist * toPixels;
|
|
6254
6317
|
let edgeWidth = 0.5;
|
|
6255
|
-
|
|
6256
|
-
if (
|
|
6318
|
+
|
|
6319
|
+
if (f.strokeWeight == 0.0) {
|
|
6320
|
+
let fillAlpha = smoothstep(-edgeWidth, edgeWidth, pxDist);
|
|
6321
|
+
var color = vec4f(f.fillColor.rgb, f.fillColor.a * fillAlpha);
|
|
6322
|
+
if (color.a < 0.01) {
|
|
6323
|
+
discard;
|
|
6324
|
+
}
|
|
6325
|
+
return color;
|
|
6326
|
+
}
|
|
6327
|
+
|
|
6328
|
+
let halfStroke = f.strokeWeight / 2.0;
|
|
6329
|
+
let fillAlpha = smoothstep(-edgeWidth, edgeWidth, pxDist - halfStroke);
|
|
6330
|
+
let strokeAlpha = smoothstep(-edgeWidth, edgeWidth, pxDist + halfStroke);
|
|
6331
|
+
var color = mix(f.strokeColor, f.fillColor, fillAlpha);
|
|
6332
|
+
color = vec4f(color.rgb, color.a * strokeAlpha);
|
|
6333
|
+
if (color.a < 0.01) {
|
|
6257
6334
|
discard;
|
|
6258
6335
|
}
|
|
6259
|
-
return
|
|
6336
|
+
return color;
|
|
6260
6337
|
}
|
|
6261
|
-
|
|
6338
|
+
`;
|
|
6339
|
+
|
|
6340
|
+
let textShader = Q5.device.createShaderModule({
|
|
6341
|
+
label: 'textShader',
|
|
6342
|
+
code: textShaderCode
|
|
6262
6343
|
});
|
|
6263
6344
|
|
|
6264
6345
|
let textBindGroupLayout = Q5.device.createBindGroupLayout({
|
|
@@ -6657,6 +6738,8 @@ fn fragmentMain(f : FragmentParams) -> @location(0) vec4f {
|
|
|
6657
6738
|
txt[3] = $._matrixIndex;
|
|
6658
6739
|
txt[4] = $._fillSet ? $._fill : 0;
|
|
6659
6740
|
txt[5] = $._stroke;
|
|
6741
|
+
txt[6] = $._strokeSet ? $._strokeWeight : 0;
|
|
6742
|
+
txt[7] = 0; // padding
|
|
6660
6743
|
|
|
6661
6744
|
textStack.push(txt);
|
|
6662
6745
|
$.drawStack.push(3, measurements.printedCharCount, $._font.index);
|
|
@@ -6733,7 +6816,7 @@ fn fragmentMain(f : FragmentParams) -> @location(0) vec4f {
|
|
|
6733
6816
|
charBuffer.unmap();
|
|
6734
6817
|
|
|
6735
6818
|
// calculate total buffer size for metadata
|
|
6736
|
-
let totalMetadataSize = textStack.length *
|
|
6819
|
+
let totalMetadataSize = textStack.length * 8 * 4;
|
|
6737
6820
|
|
|
6738
6821
|
// create a single buffer for all metadata
|
|
6739
6822
|
let textBuffer = Q5.device.createBuffer({
|
|
@@ -6747,6 +6830,8 @@ fn fragmentMain(f : FragmentParams) -> @location(0) vec4f {
|
|
|
6747
6830
|
new Float32Array(textBuffer.getMappedRange()).set(textStack.flat());
|
|
6748
6831
|
textBuffer.unmap();
|
|
6749
6832
|
|
|
6833
|
+
$._buffers.push(charBuffer, textBuffer);
|
|
6834
|
+
|
|
6750
6835
|
// create a single bind group for the text buffer and metadata buffer
|
|
6751
6836
|
$._textBindGroup = Q5.device.createBindGroup({
|
|
6752
6837
|
label: 'msdf text bind group',
|