@gjsify/webgl 0.1.8 → 0.1.9
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/lib/esm/canvas-webgl-widget.js +25 -2
- package/lib/esm/conformance/uniforms.spec.js +23 -0
- package/lib/esm/html-canvas-element.js +16 -2
- package/lib/esm/utils.js +13 -1
- package/lib/esm/webgl-context-base.js +22 -12
- package/lib/esm/webgl2-rendering-context.js +91 -1
- package/lib/esm/webgl2.spec.js +106 -0
- package/lib/types/canvas-webgl-widget.d.ts +14 -5
- package/lib/types/html-canvas-element.d.ts +4 -0
- package/lib/types/utils.d.ts +9 -0
- package/lib/types/webgl-context-base.d.ts +1 -0
- package/lib/types/webgl2-rendering-context.d.ts +4 -0
- package/package.json +10 -10
|
@@ -11,6 +11,7 @@ const CanvasWebGLWidget = GObject.registerClass(
|
|
|
11
11
|
super(params);
|
|
12
12
|
this._canvas = null;
|
|
13
13
|
this._readyCallbacks = [];
|
|
14
|
+
this._resizeCallbacks = [];
|
|
14
15
|
this._renderTag = null;
|
|
15
16
|
this._tickCallbackId = null;
|
|
16
17
|
this._frameCallback = null;
|
|
@@ -22,7 +23,7 @@ const CanvasWebGLWidget = GObject.registerClass(
|
|
|
22
23
|
this.set_required_version(3, 2);
|
|
23
24
|
this.set_has_depth_buffer(true);
|
|
24
25
|
this.set_has_stencil_buffer(true);
|
|
25
|
-
attachEventControllers(this, () => this._canvas);
|
|
26
|
+
attachEventControllers(this, () => this._canvas, { captureKeys: true });
|
|
26
27
|
const initId = this.connect("render", () => {
|
|
27
28
|
this.disconnect(initId);
|
|
28
29
|
this.make_current();
|
|
@@ -30,6 +31,7 @@ const CanvasWebGLWidget = GObject.registerClass(
|
|
|
30
31
|
if (globalThis.document?.body) {
|
|
31
32
|
globalThis.document.body.appendChild(this._canvas);
|
|
32
33
|
}
|
|
34
|
+
this._canvas.getContext("webgl2");
|
|
33
35
|
const gl = this._canvas.getContext("webgl");
|
|
34
36
|
if (gl) {
|
|
35
37
|
for (const cb of this._readyCallbacks) {
|
|
@@ -40,9 +42,14 @@ const CanvasWebGLWidget = GObject.registerClass(
|
|
|
40
42
|
return true;
|
|
41
43
|
});
|
|
42
44
|
this.connect("resize", () => {
|
|
45
|
+
const width = this.get_allocated_width();
|
|
46
|
+
const height = this.get_allocated_height();
|
|
43
47
|
if (this._canvas) {
|
|
44
48
|
this._canvas.dispatchEvent(new Event("resize"));
|
|
45
49
|
}
|
|
50
|
+
for (const cb of this._resizeCallbacks) {
|
|
51
|
+
cb(width, height);
|
|
52
|
+
}
|
|
46
53
|
if (this._frameCallback) {
|
|
47
54
|
this.requestAnimationFrame(this._frameCallback);
|
|
48
55
|
}
|
|
@@ -83,6 +90,16 @@ const CanvasWebGLWidget = GObject.registerClass(
|
|
|
83
90
|
onWebGLReady(cb) {
|
|
84
91
|
this.onReady(cb);
|
|
85
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Register a callback invoked whenever the GTK widget is resized.
|
|
95
|
+
* The callback fires alongside the native 'resize' GObject signal and
|
|
96
|
+
* after the DOM 'resize' event has been dispatched on the canvas.
|
|
97
|
+
* Canvas buffer dimensions are NOT automatically updated — consumers
|
|
98
|
+
* should set `canvas.width`/`canvas.height` themselves if desired.
|
|
99
|
+
*/
|
|
100
|
+
onResize(cb) {
|
|
101
|
+
this._resizeCallbacks.push(cb);
|
|
102
|
+
}
|
|
86
103
|
/**
|
|
87
104
|
* Schedules a single animation frame callback, matching the browser `requestAnimationFrame` API.
|
|
88
105
|
* Backed by GTK frame clock (vsync-synced) + the GLArea render signal.
|
|
@@ -94,10 +111,13 @@ const CanvasWebGLWidget = GObject.registerClass(
|
|
|
94
111
|
this._tickCallbackId = this.add_tick_callback((_widget, _frameClock) => {
|
|
95
112
|
this._tickCallbackId = null;
|
|
96
113
|
if (this._renderTag === null) {
|
|
97
|
-
this._renderTag = this.connect("render", () => {
|
|
114
|
+
this._renderTag = this.connect("render", (_widget2) => {
|
|
98
115
|
this.disconnect(this._renderTag);
|
|
99
116
|
this._renderTag = null;
|
|
100
117
|
const time = (GLib.get_monotonic_time() - this._timeOrigin) / 1e3;
|
|
118
|
+
if (globalThis.__GJSIFY_DEBUG_RAF === true) {
|
|
119
|
+
console.log(`[rAF] frame callback fires t=${time.toFixed(1)}`);
|
|
120
|
+
}
|
|
101
121
|
this._frameCallback?.(time);
|
|
102
122
|
return true;
|
|
103
123
|
});
|
|
@@ -115,6 +135,9 @@ const CanvasWebGLWidget = GObject.registerClass(
|
|
|
115
135
|
*/
|
|
116
136
|
installGlobals() {
|
|
117
137
|
globalThis.requestAnimationFrame = (cb) => this.requestAnimationFrame(cb);
|
|
138
|
+
globalThis.cancelAnimationFrame = (_id) => {
|
|
139
|
+
this._frameCallback = null;
|
|
140
|
+
};
|
|
118
141
|
const timeOrigin = this._timeOrigin;
|
|
119
142
|
globalThis.performance = {
|
|
120
143
|
now: () => (GLib.get_monotonic_time() - timeOrigin) / 1e3,
|
|
@@ -253,6 +253,29 @@ var uniforms_spec_default = async () => {
|
|
|
253
253
|
]);
|
|
254
254
|
expect(gl.getError()).toBe(gl.NO_ERROR);
|
|
255
255
|
});
|
|
256
|
+
await it("getUniformLocation resolves bare array name (without [0] suffix)", async () => {
|
|
257
|
+
const prog = makeProgram(gl, VS, FS_ARR);
|
|
258
|
+
gl.useProgram(prog);
|
|
259
|
+
const locBare = gl.getUniformLocation(prog, "u_arr");
|
|
260
|
+
expect(locBare).not.toBeNull();
|
|
261
|
+
expect(gl.getError()).toBe(gl.NO_ERROR);
|
|
262
|
+
gl.uniform1fv(locBare, [0.7, 0.8, 0.9]);
|
|
263
|
+
expect(gl.getError()).toBe(gl.NO_ERROR);
|
|
264
|
+
const val = gl.getUniform(prog, locBare);
|
|
265
|
+
expect(Math.abs(val - 0.7) < 1e-3).toBe(true);
|
|
266
|
+
});
|
|
267
|
+
await it("bare array name and indexed [0] name resolve to equivalent locations", async () => {
|
|
268
|
+
const prog = makeProgram(gl, VS, FS_ARR);
|
|
269
|
+
gl.useProgram(prog);
|
|
270
|
+
const locBare = gl.getUniformLocation(prog, "u_arr");
|
|
271
|
+
const locIndexed = gl.getUniformLocation(prog, "u_arr[0]");
|
|
272
|
+
expect(locBare).not.toBeNull();
|
|
273
|
+
expect(locIndexed).not.toBeNull();
|
|
274
|
+
gl.uniform1fv(locBare, [0.42, 0.43, 0.44]);
|
|
275
|
+
expect(gl.getError()).toBe(gl.NO_ERROR);
|
|
276
|
+
const val = gl.getUniform(prog, locIndexed);
|
|
277
|
+
expect(Math.abs(val - 0.42) < 1e-3).toBe(true);
|
|
278
|
+
});
|
|
256
279
|
await it("calling uniform* before useProgram generates INVALID_OPERATION", async () => {
|
|
257
280
|
const prog = makeProgram(gl, VS, FS_ARR);
|
|
258
281
|
gl.useProgram(null);
|
|
@@ -24,6 +24,14 @@ class HTMLCanvasElement extends BaseHTMLCanvasElement {
|
|
|
24
24
|
get clientHeight() {
|
|
25
25
|
return this.height;
|
|
26
26
|
}
|
|
27
|
+
/** CSS layout width — same as the GTK-allocated pixel width for a full-window canvas. */
|
|
28
|
+
get offsetWidth() {
|
|
29
|
+
return this.width;
|
|
30
|
+
}
|
|
31
|
+
/** CSS layout height — same as the GTK-allocated pixel height for a full-window canvas. */
|
|
32
|
+
get offsetHeight() {
|
|
33
|
+
return this.height;
|
|
34
|
+
}
|
|
27
35
|
/** Returns the underlying Gtk.GLArea. Used by WebGLRenderingContext for GLSL version detection. */
|
|
28
36
|
getGlArea() {
|
|
29
37
|
return this.gtkGlArea;
|
|
@@ -36,11 +44,17 @@ class HTMLCanvasElement extends BaseHTMLCanvasElement {
|
|
|
36
44
|
*/
|
|
37
45
|
getContext(contextId, options) {
|
|
38
46
|
if (contextId === "webgl" || contextId === "experimental-webgl") {
|
|
39
|
-
this._webgl
|
|
47
|
+
if (!this._webgl) {
|
|
48
|
+
this.gtkGlArea.make_current();
|
|
49
|
+
this._webgl = new OurWebGLRenderingContext(this, options);
|
|
50
|
+
}
|
|
40
51
|
return this._webgl;
|
|
41
52
|
}
|
|
42
53
|
if (contextId === "webgl2") {
|
|
43
|
-
this._webgl2
|
|
54
|
+
if (!this._webgl2) {
|
|
55
|
+
this.gtkGlArea.make_current();
|
|
56
|
+
this._webgl2 = new OurWebGL2RenderingContext(this, options);
|
|
57
|
+
}
|
|
44
58
|
return this._webgl2;
|
|
45
59
|
}
|
|
46
60
|
return super.getContext(contextId, options);
|
package/lib/esm/utils.js
CHANGED
|
@@ -133,7 +133,7 @@ const extractImageData = (pixels) => {
|
|
|
133
133
|
let context = null;
|
|
134
134
|
if (typeof pixels.getContext === "function") {
|
|
135
135
|
context = pixels.getContext("2d");
|
|
136
|
-
} else if (typeof pixels.isPixbuf()) {
|
|
136
|
+
} else if (typeof pixels.isPixbuf === "function" && pixels.isPixbuf()) {
|
|
137
137
|
return pixels.getImageData();
|
|
138
138
|
} else if (typeof pixels.src !== "undefined" && typeof document === "object" && typeof document.createElement === "function") {
|
|
139
139
|
const canvas = document.createElement("canvas");
|
|
@@ -190,6 +190,17 @@ function flag(options, name, dflt) {
|
|
|
190
190
|
}
|
|
191
191
|
return !!options[name];
|
|
192
192
|
}
|
|
193
|
+
function premultiplyAlpha(data) {
|
|
194
|
+
const out = new Uint8Array(data.length);
|
|
195
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
196
|
+
const a = data[i + 3] / 255;
|
|
197
|
+
out[i] = Math.round(data[i] * a);
|
|
198
|
+
out[i + 1] = Math.round(data[i + 1] * a);
|
|
199
|
+
out[i + 2] = Math.round(data[i + 2] * a);
|
|
200
|
+
out[i + 3] = data[i + 3];
|
|
201
|
+
}
|
|
202
|
+
return out;
|
|
203
|
+
}
|
|
193
204
|
export {
|
|
194
205
|
Uint8ArrayToVariant,
|
|
195
206
|
arrayToUint8Array,
|
|
@@ -205,6 +216,7 @@ export {
|
|
|
205
216
|
isTypedArray,
|
|
206
217
|
isValidString,
|
|
207
218
|
listToArray,
|
|
219
|
+
premultiplyAlpha,
|
|
208
220
|
typeSize,
|
|
209
221
|
uniformTypeSize,
|
|
210
222
|
validCubeTarget,
|
|
@@ -20,7 +20,8 @@ import {
|
|
|
20
20
|
uniformTypeSize,
|
|
21
21
|
vertexCount,
|
|
22
22
|
typeSize,
|
|
23
|
-
Uint8ArrayToVariant
|
|
23
|
+
Uint8ArrayToVariant,
|
|
24
|
+
premultiplyAlpha
|
|
24
25
|
} from "./utils.js";
|
|
25
26
|
import { getOESElementIndexUint } from "./extensions/oes-element-index-unit.js";
|
|
26
27
|
import { getOESStandardDerivatives } from "./extensions/oes-standard-derivatives.js";
|
|
@@ -97,6 +98,7 @@ class WebGLContextBase {
|
|
|
97
98
|
this._unpackAlignment = 4;
|
|
98
99
|
this._packAlignment = 4;
|
|
99
100
|
this._unpackFlipY = false;
|
|
101
|
+
this._unpackPremultAlpha = false;
|
|
100
102
|
// Viewport and scissor — tracked in JS to avoid crashing native getParameterx for array returns
|
|
101
103
|
this._viewport = new Int32Array([0, 0, 0, 0]);
|
|
102
104
|
this._scissorBox = new Int32Array([0, 0, 0, 0]);
|
|
@@ -161,6 +163,7 @@ class WebGLContextBase {
|
|
|
161
163
|
this._unpackAlignment = 4;
|
|
162
164
|
this._packAlignment = 4;
|
|
163
165
|
this._unpackFlipY = false;
|
|
166
|
+
this._unpackPremultAlpha = false;
|
|
164
167
|
this.bindBuffer(this.ARRAY_BUFFER, null);
|
|
165
168
|
this.bindBuffer(this.ELEMENT_ARRAY_BUFFER, null);
|
|
166
169
|
this.bindFramebuffer(this.FRAMEBUFFER, null);
|
|
@@ -1166,6 +1169,9 @@ class WebGLContextBase {
|
|
|
1166
1169
|
this.setError(this.INVALID_VALUE);
|
|
1167
1170
|
return;
|
|
1168
1171
|
}
|
|
1172
|
+
if (this._unpackPremultAlpha && data && format === this.RGBA) {
|
|
1173
|
+
data = premultiplyAlpha(data);
|
|
1174
|
+
}
|
|
1169
1175
|
if (this._unpackFlipY && data && width > 0 && height > 0) {
|
|
1170
1176
|
const flipped = new Uint8Array(data.length);
|
|
1171
1177
|
for (let row = 0; row < height; row++) {
|
|
@@ -1266,6 +1272,9 @@ class WebGLContextBase {
|
|
|
1266
1272
|
this.setError(this.INVALID_OPERATION);
|
|
1267
1273
|
return;
|
|
1268
1274
|
}
|
|
1275
|
+
if (this._unpackPremultAlpha && data && format === this.RGBA) {
|
|
1276
|
+
data = premultiplyAlpha(data);
|
|
1277
|
+
}
|
|
1269
1278
|
if (this._unpackFlipY && data && width > 0 && height > 0) {
|
|
1270
1279
|
const flipped = new Uint8Array(data.length);
|
|
1271
1280
|
for (let row = 0; row < height; row++) {
|
|
@@ -2817,27 +2826,32 @@ class WebGLContextBase {
|
|
|
2817
2826
|
if (/\[\d+\]$/.test(name)) {
|
|
2818
2827
|
searchName = name.replace(/\[\d+\]$/, "[0]");
|
|
2819
2828
|
}
|
|
2829
|
+
const arraySearchName = searchName + "[0]";
|
|
2820
2830
|
let info = null;
|
|
2821
2831
|
for (let i = 0; i < program._uniforms.length; ++i) {
|
|
2822
2832
|
const infoItem = program._uniforms[i];
|
|
2823
|
-
if (infoItem.name === searchName) {
|
|
2833
|
+
if (infoItem.name === searchName || infoItem.name === arraySearchName) {
|
|
2824
2834
|
info = {
|
|
2825
2835
|
size: infoItem.size,
|
|
2826
2836
|
type: infoItem.type,
|
|
2827
2837
|
name: infoItem.name
|
|
2828
2838
|
};
|
|
2839
|
+
break;
|
|
2829
2840
|
}
|
|
2830
2841
|
}
|
|
2831
2842
|
if (!info) {
|
|
2832
|
-
|
|
2843
|
+
info = { name: searchName, type: 0, size: 1 };
|
|
2833
2844
|
}
|
|
2834
2845
|
const result = new WebGLUniformLocation(
|
|
2835
2846
|
loc,
|
|
2836
2847
|
program,
|
|
2837
2848
|
info
|
|
2838
2849
|
);
|
|
2839
|
-
|
|
2840
|
-
|
|
2850
|
+
const callerBracketMatch = name.match(/\[(\d+)\]$/);
|
|
2851
|
+
const callerIndex = callerBracketMatch ? +callerBracketMatch[1] : -1;
|
|
2852
|
+
const infoIsArray = /\[0\]$/.test(info.name);
|
|
2853
|
+
if (infoIsArray && (callerIndex === -1 || callerIndex === 0)) {
|
|
2854
|
+
const baseName = info.name.replace(/\[0\]$/, "");
|
|
2841
2855
|
const arrayLocs = [];
|
|
2842
2856
|
this._saveError();
|
|
2843
2857
|
for (let i = 0; this.getError() === this.NO_ERROR; ++i) {
|
|
@@ -2852,13 +2866,8 @@ class WebGLContextBase {
|
|
|
2852
2866
|
}
|
|
2853
2867
|
this._restoreError(this.NO_ERROR);
|
|
2854
2868
|
result._array = arrayLocs;
|
|
2855
|
-
} else if (
|
|
2856
|
-
|
|
2857
|
-
if (!_regexExec || _regexExec.length <= 0) {
|
|
2858
|
-
return null;
|
|
2859
|
-
}
|
|
2860
|
-
const offset = +_regexExec[1];
|
|
2861
|
-
if (offset < 0 || offset >= info.size) {
|
|
2869
|
+
} else if (callerIndex > 0) {
|
|
2870
|
+
if (callerIndex >= info.size) {
|
|
2862
2871
|
return null;
|
|
2863
2872
|
}
|
|
2864
2873
|
}
|
|
@@ -3011,6 +3020,7 @@ class WebGLContextBase {
|
|
|
3011
3020
|
this._unpackFlipY = !!param;
|
|
3012
3021
|
return;
|
|
3013
3022
|
} else if (pname === this.UNPACK_PREMULTIPLY_ALPHA_WEBGL) {
|
|
3023
|
+
this._unpackPremultAlpha = !!param;
|
|
3014
3024
|
return;
|
|
3015
3025
|
}
|
|
3016
3026
|
return this._gl.pixelStorei(pname, param);
|
|
@@ -10,7 +10,7 @@ import { WebGLActiveInfo } from "./webgl-active-info.js";
|
|
|
10
10
|
import { WebGLTexture } from "./webgl-texture.js";
|
|
11
11
|
import { WebGLRenderbuffer } from "./webgl-renderbuffer.js";
|
|
12
12
|
import { WebGLFramebuffer } from "./webgl-framebuffer.js";
|
|
13
|
-
import { Uint8ArrayToVariant, arrayToUint8Array, vertexCount, convertPixels, extractImageData, checkObject } from "./utils.js";
|
|
13
|
+
import { Uint8ArrayToVariant, arrayToUint8Array, vertexCount, convertPixels, extractImageData, checkObject, premultiplyAlpha } from "./utils.js";
|
|
14
14
|
import { warnNotImplemented } from "@gjsify/utils";
|
|
15
15
|
class WebGL2RenderingContext extends WebGLContextBase {
|
|
16
16
|
constructor(canvas, options = {}) {
|
|
@@ -618,6 +618,9 @@ class WebGL2RenderingContext extends WebGLContextBase {
|
|
|
618
618
|
return;
|
|
619
619
|
}
|
|
620
620
|
let data = convertPixels(pixels);
|
|
621
|
+
if (this._unpackPremultAlpha && data && format === this.RGBA) {
|
|
622
|
+
data = premultiplyAlpha(data);
|
|
623
|
+
}
|
|
621
624
|
if (this._unpackFlipY && data && width > 0 && height > 0) {
|
|
622
625
|
const pixelSize = this._computePixelSize(type, format);
|
|
623
626
|
if (pixelSize > 0) {
|
|
@@ -691,6 +694,9 @@ class WebGL2RenderingContext extends WebGLContextBase {
|
|
|
691
694
|
this.setError(this.INVALID_OPERATION);
|
|
692
695
|
return;
|
|
693
696
|
}
|
|
697
|
+
if (this._unpackPremultAlpha && data && format === this.RGBA) {
|
|
698
|
+
data = premultiplyAlpha(data);
|
|
699
|
+
}
|
|
694
700
|
if (this._unpackFlipY && data && width > 0 && height > 0) {
|
|
695
701
|
const pixelSize = this._computePixelSize(type, format);
|
|
696
702
|
if (pixelSize > 0) {
|
|
@@ -724,6 +730,10 @@ class WebGL2RenderingContext extends WebGLContextBase {
|
|
|
724
730
|
if (!this._framebufferOk()) return;
|
|
725
731
|
if (count === 0 || instanceCount === 0) return;
|
|
726
732
|
if (!this._checkVertexAttribState(count + first - 1 >>> 0)) return;
|
|
733
|
+
if (globalThis.__GJSIFY_DEBUG_GL) {
|
|
734
|
+
const n = this.__drawInstCount = (this.__drawInstCount | 0) + 1;
|
|
735
|
+
if (n <= 5 || n % 100 === 0) console.log(`[WebGL] drawArraysInstanced #${n} count=${rc} instances=${instanceCount} fbo=${this._activeFramebuffer?._ ?? "_gtkFbo"}`);
|
|
736
|
+
}
|
|
727
737
|
this._native2.drawArraysInstanced(mode, first, rc, instanceCount);
|
|
728
738
|
}
|
|
729
739
|
drawElementsInstanced(mode, count, type, offset, instanceCount) {
|
|
@@ -826,7 +836,87 @@ class WebGL2RenderingContext extends WebGLContextBase {
|
|
|
826
836
|
this.drawElements(mode, count, type, offset);
|
|
827
837
|
}
|
|
828
838
|
blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) {
|
|
839
|
+
if (globalThis.__GJSIFY_DEBUG_GL) {
|
|
840
|
+
const errBefore = this._gl.getError();
|
|
841
|
+
if (errBefore !== 0) console.log(`[WebGL] blitFramebuffer PRE-ERROR 0x${errBefore.toString(16)}`);
|
|
842
|
+
}
|
|
829
843
|
this._native2.blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
|
844
|
+
if (globalThis.__GJSIFY_DEBUG_GL) {
|
|
845
|
+
const err = this._gl.getError();
|
|
846
|
+
const n = this.__blitCount = (this.__blitCount | 0) + 1;
|
|
847
|
+
if (n <= 5) console.log(`[WebGL] blitFramebuffer #${n} src=(${srcX0},${srcY0},${srcX1},${srcY1}) readFbo=${this._activeReadFramebuffer?._ ?? "_gtkFbo"} err=${err === 0 ? "OK" : "0x" + err.toString(16)}`);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
// clearBuffer{fv,iv,uiv,fi} — WebGL2 methods for clearing specific
|
|
851
|
+
// framebuffer attachments. The native Vala binding does not expose the
|
|
852
|
+
// glClearBuffer* entry points yet, so we emulate the common cases via
|
|
853
|
+
// glClearColor/glClearDepth/glClearStencil + glClear. This is equivalent
|
|
854
|
+
// when the DRAW_FRAMEBUFFER has a single attachment per buffer type,
|
|
855
|
+
// which matches Excalibur's ExcaliburGraphicsContextWebGL.blitToScreen.
|
|
856
|
+
//
|
|
857
|
+
// Buffer target constants per WebGL2 spec (not on our class):
|
|
858
|
+
// COLOR = 0x1800
|
|
859
|
+
// DEPTH = 0x1801
|
|
860
|
+
// STENCIL = 0x1802
|
|
861
|
+
// DEPTH_STENCIL = 0x84F9
|
|
862
|
+
clearBufferfv(buffer, drawbuffer, values, _srcOffset) {
|
|
863
|
+
const n2 = this._native2;
|
|
864
|
+
if (typeof n2.clearBufferfv === "function") {
|
|
865
|
+
n2.clearBufferfv(buffer, drawbuffer, Array.from(values));
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
const v = values;
|
|
869
|
+
if (buffer === 6144) {
|
|
870
|
+
const prev = this.getParameter(this.COLOR_CLEAR_VALUE);
|
|
871
|
+
this.clearColor(v[0] ?? 0, v[1] ?? 0, v[2] ?? 0, v[3] ?? 0);
|
|
872
|
+
this.clear(this.COLOR_BUFFER_BIT);
|
|
873
|
+
if (prev) this.clearColor(prev[0], prev[1], prev[2], prev[3]);
|
|
874
|
+
} else if (buffer === 6145) {
|
|
875
|
+
const prev = this.getParameter(this.DEPTH_CLEAR_VALUE);
|
|
876
|
+
this.clearDepth(v[0] ?? 1);
|
|
877
|
+
this.clear(this.DEPTH_BUFFER_BIT);
|
|
878
|
+
if (prev !== null) this.clearDepth(prev);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
clearBufferiv(buffer, drawbuffer, values, _srcOffset) {
|
|
882
|
+
const n2 = this._native2;
|
|
883
|
+
if (typeof n2.clearBufferiv === "function") {
|
|
884
|
+
n2.clearBufferiv(buffer, drawbuffer, Array.from(values));
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
if (buffer === 6146) {
|
|
888
|
+
const v = values;
|
|
889
|
+
const prev = this.getParameter(this.STENCIL_CLEAR_VALUE);
|
|
890
|
+
this.clearStencil(v[0] ?? 0);
|
|
891
|
+
this.clear(this.STENCIL_BUFFER_BIT);
|
|
892
|
+
if (prev !== null) this.clearStencil(prev);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
clearBufferuiv(buffer, drawbuffer, values, _srcOffset) {
|
|
896
|
+
const n2 = this._native2;
|
|
897
|
+
if (typeof n2.clearBufferuiv === "function") {
|
|
898
|
+
n2.clearBufferuiv(buffer, drawbuffer, Array.from(values));
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
void buffer;
|
|
902
|
+
void drawbuffer;
|
|
903
|
+
}
|
|
904
|
+
clearBufferfi(buffer, drawbuffer, depth, stencil) {
|
|
905
|
+
const n2 = this._native2;
|
|
906
|
+
if (typeof n2.clearBufferfi === "function") {
|
|
907
|
+
n2.clearBufferfi(buffer, drawbuffer, depth, stencil);
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
if (buffer === 34041) {
|
|
911
|
+
const prevDepth = this.getParameter(this.DEPTH_CLEAR_VALUE);
|
|
912
|
+
const prevStencil = this.getParameter(this.STENCIL_CLEAR_VALUE);
|
|
913
|
+
this.clearDepth(depth);
|
|
914
|
+
this.clearStencil(stencil);
|
|
915
|
+
this.clear(this.DEPTH_BUFFER_BIT | this.STENCIL_BUFFER_BIT);
|
|
916
|
+
if (prevDepth !== null) this.clearDepth(prevDepth);
|
|
917
|
+
if (prevStencil !== null) this.clearStencil(prevStencil);
|
|
918
|
+
}
|
|
919
|
+
void drawbuffer;
|
|
830
920
|
}
|
|
831
921
|
invalidateFramebuffer(target, attachments) {
|
|
832
922
|
this._native2.invalidateFramebuffer(target, Array.from(attachments));
|
package/lib/esm/webgl2.spec.js
CHANGED
|
@@ -1126,6 +1126,112 @@ void main(){c0=vec4(1.,0.,0.,1.);c1=vec4(0.,0.,1.,1.);}`;
|
|
|
1126
1126
|
gl2.deleteProgram(prog);
|
|
1127
1127
|
});
|
|
1128
1128
|
});
|
|
1129
|
+
await describe("WebGL2 Excalibur-style VAO draw + READ/DRAW blitToScreen", async () => {
|
|
1130
|
+
beforeEach(async () => {
|
|
1131
|
+
glArea.make_current();
|
|
1132
|
+
});
|
|
1133
|
+
await it("VAO draw to source FBO survives clearBufferfv+blit pipeline", async () => {
|
|
1134
|
+
const W = 4;
|
|
1135
|
+
const H = 4;
|
|
1136
|
+
const gl = gl2;
|
|
1137
|
+
const srcFbo = gl2.createFramebuffer();
|
|
1138
|
+
const srcTex = gl2.createTexture();
|
|
1139
|
+
gl2.bindTexture(gl2.TEXTURE_2D, srcTex);
|
|
1140
|
+
gl2.texImage2D(gl2.TEXTURE_2D, 0, gl2.RGBA, W, H, 0, gl2.RGBA, gl2.UNSIGNED_BYTE, null);
|
|
1141
|
+
gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MIN_FILTER, gl2.NEAREST);
|
|
1142
|
+
gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MAG_FILTER, gl2.NEAREST);
|
|
1143
|
+
gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_WRAP_S, gl2.CLAMP_TO_EDGE);
|
|
1144
|
+
gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_WRAP_T, gl2.CLAMP_TO_EDGE);
|
|
1145
|
+
gl2.bindTexture(gl2.TEXTURE_2D, null);
|
|
1146
|
+
gl2.bindFramebuffer(gl2.FRAMEBUFFER, srcFbo);
|
|
1147
|
+
gl2.framebufferTexture2D(gl2.FRAMEBUFFER, gl2.COLOR_ATTACHMENT0, gl2.TEXTURE_2D, srcTex, 0);
|
|
1148
|
+
expect(gl2.checkFramebufferStatus(gl2.FRAMEBUFFER)).toBe(gl2.FRAMEBUFFER_COMPLETE);
|
|
1149
|
+
const dstFbo = gl2.createFramebuffer();
|
|
1150
|
+
const dstTex = gl2.createTexture();
|
|
1151
|
+
gl2.bindTexture(gl2.TEXTURE_2D, dstTex);
|
|
1152
|
+
gl2.texImage2D(gl2.TEXTURE_2D, 0, gl2.RGBA, W, H, 0, gl2.RGBA, gl2.UNSIGNED_BYTE, null);
|
|
1153
|
+
gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MIN_FILTER, gl2.NEAREST);
|
|
1154
|
+
gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MAG_FILTER, gl2.NEAREST);
|
|
1155
|
+
gl2.bindTexture(gl2.TEXTURE_2D, null);
|
|
1156
|
+
gl2.bindFramebuffer(gl2.FRAMEBUFFER, dstFbo);
|
|
1157
|
+
gl2.framebufferTexture2D(gl2.FRAMEBUFFER, gl2.COLOR_ATTACHMENT0, gl2.TEXTURE_2D, dstTex, 0);
|
|
1158
|
+
expect(gl2.checkFramebufferStatus(gl2.FRAMEBUFFER)).toBe(gl2.FRAMEBUFFER_COMPLETE);
|
|
1159
|
+
gl2.bindFramebuffer(gl2.FRAMEBUFFER, null);
|
|
1160
|
+
const vs300 = `#version 300 es
|
|
1161
|
+
in vec2 a_pos;
|
|
1162
|
+
void main(){gl_Position=vec4(a_pos,0.,1.);}`;
|
|
1163
|
+
const fs300 = `#version 300 es
|
|
1164
|
+
precision mediump float;
|
|
1165
|
+
out vec4 c;
|
|
1166
|
+
void main(){c=vec4(0.,1.,0.,1.);}`;
|
|
1167
|
+
const prog = makeProgram(gl, vs300, fs300);
|
|
1168
|
+
expect(gl2.getProgramParameter(prog, gl2.LINK_STATUS)).toBeTruthy();
|
|
1169
|
+
const vao = gl2.createVertexArray();
|
|
1170
|
+
gl2.bindVertexArray(vao);
|
|
1171
|
+
const vbo = gl2.createBuffer();
|
|
1172
|
+
gl2.bindBuffer(gl2.ARRAY_BUFFER, vbo);
|
|
1173
|
+
gl2.bufferData(gl2.ARRAY_BUFFER, new Float32Array([
|
|
1174
|
+
-1,
|
|
1175
|
+
-1,
|
|
1176
|
+
3,
|
|
1177
|
+
-1,
|
|
1178
|
+
-1,
|
|
1179
|
+
3
|
|
1180
|
+
// large triangle covering clip space
|
|
1181
|
+
]), gl2.STATIC_DRAW);
|
|
1182
|
+
const aPos = gl2.getAttribLocation(prog, "a_pos");
|
|
1183
|
+
gl2.enableVertexAttribArray(aPos);
|
|
1184
|
+
gl2.vertexAttribPointer(aPos, 2, gl2.FLOAT, false, 0, 0);
|
|
1185
|
+
gl2.bindVertexArray(null);
|
|
1186
|
+
gl2.bindFramebuffer(gl2.FRAMEBUFFER, srcFbo);
|
|
1187
|
+
gl2.viewport(0, 0, W, H);
|
|
1188
|
+
gl2.clearColor(0, 0, 1, 1);
|
|
1189
|
+
gl2.clear(gl2.COLOR_BUFFER_BIT);
|
|
1190
|
+
gl2.useProgram(prog);
|
|
1191
|
+
gl2.bindVertexArray(vao);
|
|
1192
|
+
gl2.drawArrays(gl2.TRIANGLES, 0, 3);
|
|
1193
|
+
gl2.bindVertexArray(null);
|
|
1194
|
+
expect(gl2.getError()).toBe(gl2.NO_ERROR);
|
|
1195
|
+
const READ_FRAMEBUFFER = 36008;
|
|
1196
|
+
const DRAW_FRAMEBUFFER = 36009;
|
|
1197
|
+
gl2.bindFramebuffer(READ_FRAMEBUFFER, srcFbo);
|
|
1198
|
+
gl2.bindFramebuffer(DRAW_FRAMEBUFFER, dstFbo);
|
|
1199
|
+
expect(gl2.getError()).toBe(gl2.NO_ERROR);
|
|
1200
|
+
gl2.clearBufferfv(gl2.COLOR, 0, [0, 0, 1, 1]);
|
|
1201
|
+
expect(gl2.getError()).toBe(gl2.NO_ERROR);
|
|
1202
|
+
gl2.blitFramebuffer(0, 0, W, H, 0, 0, W, H, gl2.COLOR_BUFFER_BIT, gl2.LINEAR);
|
|
1203
|
+
expect(gl2.getError()).toBe(gl2.NO_ERROR);
|
|
1204
|
+
gl2.bindFramebuffer(gl2.FRAMEBUFFER, dstFbo);
|
|
1205
|
+
const pixels = new Uint8Array(4);
|
|
1206
|
+
gl2.readPixels(0, 0, 1, 1, gl2.RGBA, gl2.UNSIGNED_BYTE, pixels);
|
|
1207
|
+
expect(gl2.getError()).toBe(gl2.NO_ERROR);
|
|
1208
|
+
gl2.bindFramebuffer(gl2.FRAMEBUFFER, srcFbo);
|
|
1209
|
+
const srcPixels = new Uint8Array(4);
|
|
1210
|
+
gl2.readPixels(0, 0, 1, 1, gl2.RGBA, gl2.UNSIGNED_BYTE, srcPixels);
|
|
1211
|
+
expect(gl2.getError()).toBe(gl2.NO_ERROR);
|
|
1212
|
+
gl2.bindVertexArray(null);
|
|
1213
|
+
gl2.deleteVertexArray(vao);
|
|
1214
|
+
gl2.deleteBuffer(vbo);
|
|
1215
|
+
gl2.deleteProgram(prog);
|
|
1216
|
+
gl2.bindFramebuffer(gl2.FRAMEBUFFER, srcFbo);
|
|
1217
|
+
gl2.framebufferTexture2D(gl2.FRAMEBUFFER, gl2.COLOR_ATTACHMENT0, gl2.TEXTURE_2D, null, 0);
|
|
1218
|
+
gl2.bindFramebuffer(gl2.FRAMEBUFFER, dstFbo);
|
|
1219
|
+
gl2.framebufferTexture2D(gl2.FRAMEBUFFER, gl2.COLOR_ATTACHMENT0, gl2.TEXTURE_2D, null, 0);
|
|
1220
|
+
gl2.bindFramebuffer(gl2.FRAMEBUFFER, null);
|
|
1221
|
+
gl2.deleteTexture(srcTex);
|
|
1222
|
+
gl2.deleteTexture(dstTex);
|
|
1223
|
+
gl2.deleteFramebuffer(srcFbo);
|
|
1224
|
+
gl2.deleteFramebuffer(dstFbo);
|
|
1225
|
+
expect(pixels[0]).toBe(0);
|
|
1226
|
+
expect(pixels[1]).toBe(255);
|
|
1227
|
+
expect(pixels[2]).toBe(0);
|
|
1228
|
+
expect(pixels[3]).toBe(255);
|
|
1229
|
+
expect(srcPixels[0]).toBe(0);
|
|
1230
|
+
expect(srcPixels[1]).toBe(255);
|
|
1231
|
+
expect(srcPixels[2]).toBe(0);
|
|
1232
|
+
expect(srcPixels[3]).toBe(255);
|
|
1233
|
+
});
|
|
1234
|
+
});
|
|
1129
1235
|
await describe("WebGL2 bufferSubData with UNIFORM_BUFFER", async () => {
|
|
1130
1236
|
beforeEach(async () => {
|
|
1131
1237
|
glArea.make_current();
|
|
@@ -27,6 +27,7 @@ export declare const CanvasWebGLWidget: {
|
|
|
27
27
|
new (params?: Partial<Gtk.GLArea.ConstructorProps>): {
|
|
28
28
|
_canvas: OurHTMLCanvasElement | null;
|
|
29
29
|
_readyCallbacks: WebGLReadyCallback[];
|
|
30
|
+
_resizeCallbacks: ((width: number, height: number) => void)[];
|
|
30
31
|
_renderTag: number | null;
|
|
31
32
|
_tickCallbackId: number | null;
|
|
32
33
|
_frameCallback: FrameRequestCallback | null;
|
|
@@ -42,6 +43,14 @@ export declare const CanvasWebGLWidget: {
|
|
|
42
43
|
* @deprecated Use `onReady()` instead.
|
|
43
44
|
*/
|
|
44
45
|
onWebGLReady(cb: WebGLReadyCallback): void;
|
|
46
|
+
/**
|
|
47
|
+
* Register a callback invoked whenever the GTK widget is resized.
|
|
48
|
+
* The callback fires alongside the native 'resize' GObject signal and
|
|
49
|
+
* after the DOM 'resize' event has been dispatched on the canvas.
|
|
50
|
+
* Canvas buffer dimensions are NOT automatically updated — consumers
|
|
51
|
+
* should set `canvas.width`/`canvas.height` themselves if desired.
|
|
52
|
+
*/
|
|
53
|
+
onResize(cb: (width: number, height: number) => void): void;
|
|
45
54
|
/**
|
|
46
55
|
* Schedules a single animation frame callback, matching the browser `requestAnimationFrame` API.
|
|
47
56
|
* Backed by GTK frame clock (vsync-synced) + the GLArea render signal.
|
|
@@ -141,7 +150,7 @@ export declare const CanvasWebGLWidget: {
|
|
|
141
150
|
vfunc_get_id(): string;
|
|
142
151
|
vfunc_get_internal_child<T = GObject.Object>(builder: Gtk.Builder, childname: string): T;
|
|
143
152
|
vfunc_parser_finished(builder: Gtk.Builder): void;
|
|
144
|
-
vfunc_set_buildable_property(builder: Gtk.Builder, name: string, value:
|
|
153
|
+
vfunc_set_buildable_property(builder: Gtk.Builder, name: string, value: unknown): void;
|
|
145
154
|
vfunc_set_id(id: string): void;
|
|
146
155
|
bind_property(source_property: string, target: GObject.Object, target_property: string, flags: GObject.BindingFlags | null): GObject.Binding;
|
|
147
156
|
bind_property_full(source_property: string, target: GObject.Object, target_property: string, flags: GObject.BindingFlags | null, transform_to?: GObject.BindingTransformFunc | null, transform_from?: GObject.BindingTransformFunc | null, notify?: GLib.DestroyNotify | null): GObject.Binding;
|
|
@@ -169,9 +178,9 @@ export declare const CanvasWebGLWidget: {
|
|
|
169
178
|
vfunc_dispatch_properties_changed(n_pspecs: number, pspecs: GObject.ParamSpec): void;
|
|
170
179
|
vfunc_dispose(): void;
|
|
171
180
|
vfunc_finalize(): void;
|
|
172
|
-
vfunc_get_property(property_id: number, value:
|
|
181
|
+
vfunc_get_property(property_id: number, value: unknown, pspec: GObject.ParamSpec): void;
|
|
173
182
|
vfunc_notify(pspec: GObject.ParamSpec): void;
|
|
174
|
-
vfunc_set_property(property_id: number, value:
|
|
183
|
+
vfunc_set_property(property_id: number, value: unknown, pspec: GObject.ParamSpec): void;
|
|
175
184
|
disconnect(id: number): void;
|
|
176
185
|
set(properties: {
|
|
177
186
|
[key: string]: any;
|
|
@@ -477,7 +486,7 @@ export declare const CanvasWebGLWidget: {
|
|
|
477
486
|
set_default_direction(dir: Gtk.TextDirection): void;
|
|
478
487
|
add_shortcut(shortcut: Gtk.Shortcut): void;
|
|
479
488
|
bind_template_callback_full(callback_name: string, callback_symbol: GObject.Callback): void;
|
|
480
|
-
bind_template_child_full(name: string, internal_child: boolean, struct_offset: number): void;
|
|
489
|
+
bind_template_child_full(name: string, internal_child: boolean, struct_offset: bigint | number): void;
|
|
481
490
|
get_accessible_role(): Gtk.AccessibleRole;
|
|
482
491
|
get_activate_signal(): number;
|
|
483
492
|
get_css_name(): string;
|
|
@@ -494,7 +503,7 @@ export declare const CanvasWebGLWidget: {
|
|
|
494
503
|
set_template_from_resource(resource_name: string): void;
|
|
495
504
|
set_template_scope(scope: Gtk.BuilderScope): void;
|
|
496
505
|
newv(object_type: GObject.GType, parameters: GObject.Parameter[]): GObject.Object;
|
|
497
|
-
compat_control(what: number, data?: any | null): number;
|
|
506
|
+
compat_control(what: bigint | number, data?: any | null): number;
|
|
498
507
|
interface_find_property(g_iface: GObject.TypeInterface, property_name: string): GObject.ParamSpec;
|
|
499
508
|
interface_install_property(g_iface: GObject.TypeInterface, pspec: GObject.ParamSpec): void;
|
|
500
509
|
interface_list_properties(g_iface: GObject.TypeInterface): GObject.ParamSpec[];
|
|
@@ -15,6 +15,10 @@ export declare class HTMLCanvasElement extends BaseHTMLCanvasElement {
|
|
|
15
15
|
set height(_height: number);
|
|
16
16
|
get clientWidth(): number;
|
|
17
17
|
get clientHeight(): number;
|
|
18
|
+
/** CSS layout width — same as the GTK-allocated pixel width for a full-window canvas. */
|
|
19
|
+
get offsetWidth(): number;
|
|
20
|
+
/** CSS layout height — same as the GTK-allocated pixel height for a full-window canvas. */
|
|
21
|
+
get offsetHeight(): number;
|
|
18
22
|
/** Returns the underlying Gtk.GLArea. Used by WebGLRenderingContext for GLSL version detection. */
|
|
19
23
|
getGlArea(): Gtk.GLArea;
|
|
20
24
|
/**
|
package/lib/types/utils.d.ts
CHANGED
|
@@ -28,3 +28,12 @@ export declare function convertPixels(pixels: ArrayBuffer | Uint8Array | Uint16A
|
|
|
28
28
|
export declare function checkFormat(gl: WebGLContextBase, format: GLenum): format is 6406 | 6407 | 6408 | 6409 | 6410;
|
|
29
29
|
export declare function validCubeTarget(gl: WebGLContextBase, target: GLenum): target is 34069 | 34070 | 34071 | 34072 | 34073 | 34074;
|
|
30
30
|
export declare function flag<T = Record<string, any>>(options: T, name: keyof T, dflt: boolean): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Premultiply RGB channels by the alpha channel (in-place copy).
|
|
33
|
+
* Required when UNPACK_PREMULTIPLY_ALPHA_WEBGL is set.
|
|
34
|
+
* Excalibur uses blendFunc(ONE, ONE_MINUS_SRC_ALPHA) (premultiplied alpha
|
|
35
|
+
* blending), so textures must have RGB already multiplied by alpha before
|
|
36
|
+
* upload. Without this, transparent-background PNGs (alpha=0 but RGB=255)
|
|
37
|
+
* bleed through as white rectangles.
|
|
38
|
+
*/
|
|
39
|
+
export declare function premultiplyAlpha(data: Uint8Array): Uint8Array;
|
|
@@ -152,6 +152,10 @@ export declare class WebGL2RenderingContext extends WebGLContextBase implements
|
|
|
152
152
|
drawBuffers(buffers: GLenum[]): void;
|
|
153
153
|
drawRangeElements(mode: GLenum, start: GLuint, end: GLuint, count: GLsizei, type: GLenum, offset: GLintptr): void;
|
|
154
154
|
blitFramebuffer(srcX0: GLint, srcY0: GLint, srcX1: GLint, srcY1: GLint, dstX0: GLint, dstY0: GLint, dstX1: GLint, dstY1: GLint, mask: GLbitfield, filter: GLenum): void;
|
|
155
|
+
clearBufferfv(buffer: GLenum, drawbuffer: GLint, values: Float32List, _srcOffset?: GLuint): void;
|
|
156
|
+
clearBufferiv(buffer: GLenum, drawbuffer: GLint, values: Int32List, _srcOffset?: GLuint): void;
|
|
157
|
+
clearBufferuiv(buffer: GLenum, drawbuffer: GLint, values: Uint32List, _srcOffset?: GLuint): void;
|
|
158
|
+
clearBufferfi(buffer: GLenum, drawbuffer: GLint, depth: GLfloat, stencil: GLint): void;
|
|
155
159
|
invalidateFramebuffer(target: GLenum, attachments: GLenum[]): void;
|
|
156
160
|
invalidateSubFramebuffer(target: GLenum, attachments: GLenum[], x: GLint, y: GLint, width: GLsizei, height: GLsizei): void;
|
|
157
161
|
readBuffer(src: GLenum): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/webgl",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "WebGL module for Gjs",
|
|
5
5
|
"module": "lib/esm/index.js",
|
|
6
6
|
"types": "lib/types/index.d.ts",
|
|
@@ -39,19 +39,19 @@
|
|
|
39
39
|
"WebGL"
|
|
40
40
|
],
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@gjsify/cli": "^0.1.
|
|
43
|
-
"@gjsify/unit": "^0.1.
|
|
42
|
+
"@gjsify/cli": "^0.1.9",
|
|
43
|
+
"@gjsify/unit": "^0.1.9",
|
|
44
44
|
"@types/bit-twiddle": "^1.0.3",
|
|
45
|
-
"@types/node": "^25.
|
|
45
|
+
"@types/node": "^25.6.0",
|
|
46
46
|
"typescript": "^6.0.2"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@girs/gjs": "^4.0.0-rc.
|
|
50
|
-
"@girs/gtk-4.0": "^4.23.0-4.0.0-rc.
|
|
51
|
-
"@girs/gwebgl-0.1": "^0.1.0-4.0.0-rc.
|
|
52
|
-
"@gjsify/dom-elements": "^0.1.
|
|
53
|
-
"@gjsify/event-bridge": "^0.1.
|
|
54
|
-
"@gjsify/utils": "^0.1.
|
|
49
|
+
"@girs/gjs": "^4.0.0-rc.2",
|
|
50
|
+
"@girs/gtk-4.0": "^4.23.0-4.0.0-rc.2",
|
|
51
|
+
"@girs/gwebgl-0.1": "^0.1.0-4.0.0-rc.2",
|
|
52
|
+
"@gjsify/dom-elements": "^0.1.9",
|
|
53
|
+
"@gjsify/event-bridge": "^0.1.9",
|
|
54
|
+
"@gjsify/utils": "^0.1.9",
|
|
55
55
|
"bit-twiddle": "^1.0.2",
|
|
56
56
|
"glsl-tokenizer": "^2.1.5"
|
|
57
57
|
}
|