@vectojs/core 1.16.1 → 1.16.3
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/dist/{chunk-IYPLG4Z4.js → chunk-L4SWVP2H.js} +236 -123
- package/dist/{chunk-JFU56BX4.mjs → chunk-QS3CUV7H.mjs} +236 -123
- package/dist/index.js +50 -16
- package/dist/index.mjs +44 -10
- package/dist/renderer.js +2 -2
- package/dist/renderer.mjs +1 -1
- package/dist/tree/Scene.d.ts +33 -1
- package/package.json +1 -1
|
@@ -827,8 +827,6 @@ function fromCanvas(css) {
|
|
|
827
827
|
function parseColorToRGBA(css) {
|
|
828
828
|
const hit = cache.get(css);
|
|
829
829
|
if (hit) {
|
|
830
|
-
cache.delete(css);
|
|
831
|
-
cache.set(css, hit);
|
|
832
830
|
return hit;
|
|
833
831
|
}
|
|
834
832
|
const trimmed = css.trim();
|
|
@@ -843,12 +841,26 @@ function parseColorToRGBA(css) {
|
|
|
843
841
|
// src/renderer/WebGLPointRenderer.ts
|
|
844
842
|
var FLOATS_PER_POINT = 7;
|
|
845
843
|
var POINT_STRIDE = FLOATS_PER_POINT * 4;
|
|
844
|
+
var VERTS_PER_QUAD = 4;
|
|
845
|
+
var INDICES_PER_QUAD = 6;
|
|
846
846
|
var FLOATS_PER_RECT_VERT = 6;
|
|
847
847
|
var RECT_VERT_STRIDE = FLOATS_PER_RECT_VERT * 4;
|
|
848
|
-
var VERTS_PER_RECT = 6;
|
|
849
848
|
var FLOATS_PER_SPRITE_VERT = 8;
|
|
850
849
|
var SPRITE_VERT_STRIDE = FLOATS_PER_SPRITE_VERT * 4;
|
|
851
|
-
|
|
850
|
+
function buildQuadIndices(quads) {
|
|
851
|
+
const out = new Uint32Array(quads * INDICES_PER_QUAD);
|
|
852
|
+
for (let i = 0; i < quads; i++) {
|
|
853
|
+
const v = i * VERTS_PER_QUAD;
|
|
854
|
+
const o = i * INDICES_PER_QUAD;
|
|
855
|
+
out[o] = v;
|
|
856
|
+
out[o + 1] = v + 1;
|
|
857
|
+
out[o + 2] = v + 2;
|
|
858
|
+
out[o + 3] = v;
|
|
859
|
+
out[o + 4] = v + 2;
|
|
860
|
+
out[o + 5] = v + 3;
|
|
861
|
+
}
|
|
862
|
+
return out;
|
|
863
|
+
}
|
|
852
864
|
var POINT_VERT = `#version 300 es
|
|
853
865
|
in vec2 a_pos;
|
|
854
866
|
in float a_radius;
|
|
@@ -976,6 +988,120 @@ function link(gl, vsSrc, fsSrc) {
|
|
|
976
988
|
}
|
|
977
989
|
return program;
|
|
978
990
|
}
|
|
991
|
+
function writeQuad(out, o, x, y, width, height, u0, v0, u1, v1, r, g, b, al, rotation) {
|
|
992
|
+
let x1;
|
|
993
|
+
let y1;
|
|
994
|
+
let x2;
|
|
995
|
+
let y2;
|
|
996
|
+
let x3;
|
|
997
|
+
let y3;
|
|
998
|
+
if (rotation === 0) {
|
|
999
|
+
x1 = x + width;
|
|
1000
|
+
y1 = y;
|
|
1001
|
+
x2 = x + width;
|
|
1002
|
+
y2 = y + height;
|
|
1003
|
+
x3 = x;
|
|
1004
|
+
y3 = y + height;
|
|
1005
|
+
} else {
|
|
1006
|
+
const s = Math.sin(rotation);
|
|
1007
|
+
const c = Math.cos(rotation);
|
|
1008
|
+
const wc = width * c;
|
|
1009
|
+
const ws = width * s;
|
|
1010
|
+
const hc = height * c;
|
|
1011
|
+
const hs = height * s;
|
|
1012
|
+
x1 = x + wc;
|
|
1013
|
+
y1 = y + ws;
|
|
1014
|
+
x2 = x + wc - hs;
|
|
1015
|
+
y2 = y + ws + hc;
|
|
1016
|
+
x3 = x - hs;
|
|
1017
|
+
y3 = y + hc;
|
|
1018
|
+
}
|
|
1019
|
+
out[o] = x;
|
|
1020
|
+
out[o + 1] = y;
|
|
1021
|
+
out[o + 2] = u0;
|
|
1022
|
+
out[o + 3] = v0;
|
|
1023
|
+
out[o + 4] = r;
|
|
1024
|
+
out[o + 5] = g;
|
|
1025
|
+
out[o + 6] = b;
|
|
1026
|
+
out[o + 7] = al;
|
|
1027
|
+
out[o + 8] = x1;
|
|
1028
|
+
out[o + 9] = y1;
|
|
1029
|
+
out[o + 10] = u1;
|
|
1030
|
+
out[o + 11] = v0;
|
|
1031
|
+
out[o + 12] = r;
|
|
1032
|
+
out[o + 13] = g;
|
|
1033
|
+
out[o + 14] = b;
|
|
1034
|
+
out[o + 15] = al;
|
|
1035
|
+
out[o + 16] = x2;
|
|
1036
|
+
out[o + 17] = y2;
|
|
1037
|
+
out[o + 18] = u1;
|
|
1038
|
+
out[o + 19] = v1;
|
|
1039
|
+
out[o + 20] = r;
|
|
1040
|
+
out[o + 21] = g;
|
|
1041
|
+
out[o + 22] = b;
|
|
1042
|
+
out[o + 23] = al;
|
|
1043
|
+
out[o + 24] = x3;
|
|
1044
|
+
out[o + 25] = y3;
|
|
1045
|
+
out[o + 26] = u0;
|
|
1046
|
+
out[o + 27] = v1;
|
|
1047
|
+
out[o + 28] = r;
|
|
1048
|
+
out[o + 29] = g;
|
|
1049
|
+
out[o + 30] = b;
|
|
1050
|
+
out[o + 31] = al;
|
|
1051
|
+
}
|
|
1052
|
+
function writeRectQuad(out, o, x, y, width, height, r, g, b, al, rotation) {
|
|
1053
|
+
let x1;
|
|
1054
|
+
let y1;
|
|
1055
|
+
let x2;
|
|
1056
|
+
let y2;
|
|
1057
|
+
let x3;
|
|
1058
|
+
let y3;
|
|
1059
|
+
if (rotation === 0) {
|
|
1060
|
+
x1 = x + width;
|
|
1061
|
+
y1 = y;
|
|
1062
|
+
x2 = x + width;
|
|
1063
|
+
y2 = y + height;
|
|
1064
|
+
x3 = x;
|
|
1065
|
+
y3 = y + height;
|
|
1066
|
+
} else {
|
|
1067
|
+
const s = Math.sin(rotation);
|
|
1068
|
+
const c = Math.cos(rotation);
|
|
1069
|
+
const wc = width * c;
|
|
1070
|
+
const ws = width * s;
|
|
1071
|
+
const hc = height * c;
|
|
1072
|
+
const hs = height * s;
|
|
1073
|
+
x1 = x + wc;
|
|
1074
|
+
y1 = y + ws;
|
|
1075
|
+
x2 = x + wc - hs;
|
|
1076
|
+
y2 = y + ws + hc;
|
|
1077
|
+
x3 = x - hs;
|
|
1078
|
+
y3 = y + hc;
|
|
1079
|
+
}
|
|
1080
|
+
out[o] = x;
|
|
1081
|
+
out[o + 1] = y;
|
|
1082
|
+
out[o + 2] = r;
|
|
1083
|
+
out[o + 3] = g;
|
|
1084
|
+
out[o + 4] = b;
|
|
1085
|
+
out[o + 5] = al;
|
|
1086
|
+
out[o + 6] = x1;
|
|
1087
|
+
out[o + 7] = y1;
|
|
1088
|
+
out[o + 8] = r;
|
|
1089
|
+
out[o + 9] = g;
|
|
1090
|
+
out[o + 10] = b;
|
|
1091
|
+
out[o + 11] = al;
|
|
1092
|
+
out[o + 12] = x2;
|
|
1093
|
+
out[o + 13] = y2;
|
|
1094
|
+
out[o + 14] = r;
|
|
1095
|
+
out[o + 15] = g;
|
|
1096
|
+
out[o + 16] = b;
|
|
1097
|
+
out[o + 17] = al;
|
|
1098
|
+
out[o + 18] = x3;
|
|
1099
|
+
out[o + 19] = y3;
|
|
1100
|
+
out[o + 20] = r;
|
|
1101
|
+
out[o + 21] = g;
|
|
1102
|
+
out[o + 22] = b;
|
|
1103
|
+
out[o + 23] = al;
|
|
1104
|
+
}
|
|
979
1105
|
function grow(data, needed) {
|
|
980
1106
|
if (needed <= data.length) return data;
|
|
981
1107
|
let cap = data.length;
|
|
@@ -1070,6 +1196,22 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1070
1196
|
gl.enableVertexAttribArray(cATint);
|
|
1071
1197
|
gl.vertexAttribPointer(cATint, 4, gl.FLOAT, false, SPRITE_VERT_STRIDE, 16);
|
|
1072
1198
|
gl.bindVertexArray(null);
|
|
1199
|
+
const quadIndexBuffer = gl.createBuffer();
|
|
1200
|
+
let quadIndexCapacity = 0;
|
|
1201
|
+
const ensureQuadIndices = (quads) => {
|
|
1202
|
+
if (quads <= quadIndexCapacity) return;
|
|
1203
|
+
let cap = quadIndexCapacity || 256;
|
|
1204
|
+
while (cap < quads) cap *= 2;
|
|
1205
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, quadIndexBuffer);
|
|
1206
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, buildQuadIndices(cap), gl.STATIC_DRAW);
|
|
1207
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
|
|
1208
|
+
quadIndexCapacity = cap;
|
|
1209
|
+
};
|
|
1210
|
+
for (const vao of [rectVAO, spriteVAO, glyphVAO, circleQuadVAO]) {
|
|
1211
|
+
gl.bindVertexArray(vao);
|
|
1212
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, quadIndexBuffer);
|
|
1213
|
+
gl.bindVertexArray(null);
|
|
1214
|
+
}
|
|
1073
1215
|
let texture = null;
|
|
1074
1216
|
let textureSource = null;
|
|
1075
1217
|
let msdfTexture = null;
|
|
@@ -1077,15 +1219,13 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1077
1219
|
let distanceRange = 4;
|
|
1078
1220
|
let pointData = new Float32Array(FLOATS_PER_POINT * 1024);
|
|
1079
1221
|
let pointCount = 0;
|
|
1080
|
-
let rectData = new Float32Array(FLOATS_PER_RECT_VERT *
|
|
1222
|
+
let rectData = new Float32Array(FLOATS_PER_RECT_VERT * VERTS_PER_QUAD * 256);
|
|
1081
1223
|
let rectCount = 0;
|
|
1082
|
-
let spriteData = new Float32Array(FLOATS_PER_SPRITE_VERT *
|
|
1224
|
+
let spriteData = new Float32Array(FLOATS_PER_SPRITE_VERT * VERTS_PER_QUAD * 256);
|
|
1083
1225
|
let spriteCount = 0;
|
|
1084
|
-
let glyphData = new Float32Array(FLOATS_PER_SPRITE_VERT *
|
|
1226
|
+
let glyphData = new Float32Array(FLOATS_PER_SPRITE_VERT * VERTS_PER_QUAD * 1024);
|
|
1085
1227
|
let glyphCount = 0;
|
|
1086
|
-
let circleQuadData = new Float32Array(
|
|
1087
|
-
FLOATS_PER_SPRITE_VERT * VERTS_PER_SPRITE * 64
|
|
1088
|
-
);
|
|
1228
|
+
let circleQuadData = new Float32Array(FLOATS_PER_SPRITE_VERT * VERTS_PER_QUAD * 64);
|
|
1089
1229
|
let circleQuadCount = 0;
|
|
1090
1230
|
let logicalW = 0;
|
|
1091
1231
|
let logicalH = 0;
|
|
@@ -1095,7 +1235,7 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1095
1235
|
const maxPointSize = pointSizeRange ? pointSizeRange[1] : Infinity;
|
|
1096
1236
|
const drawGlyphs = () => {
|
|
1097
1237
|
if (glyphCount === 0 || !msdfTexture) return;
|
|
1098
|
-
const floats = glyphCount *
|
|
1238
|
+
const floats = glyphCount * VERTS_PER_QUAD * FLOATS_PER_SPRITE_VERT;
|
|
1099
1239
|
gl.useProgram(msdfProgram);
|
|
1100
1240
|
gl.bindVertexArray(glyphVAO);
|
|
1101
1241
|
gl.bindBuffer(gl.ARRAY_BUFFER, glyphBuffer);
|
|
@@ -1105,7 +1245,8 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1105
1245
|
gl.uniform1i(gUTex, 0);
|
|
1106
1246
|
gl.uniform2f(gURes, logicalW, logicalH);
|
|
1107
1247
|
gl.uniform1f(gURange, distanceRange);
|
|
1108
|
-
|
|
1248
|
+
ensureQuadIndices(glyphCount);
|
|
1249
|
+
gl.drawElements(gl.TRIANGLES, glyphCount * INDICES_PER_QUAD, gl.UNSIGNED_INT, 0);
|
|
1109
1250
|
gl.bindVertexArray(null);
|
|
1110
1251
|
glyphCount = 0;
|
|
1111
1252
|
};
|
|
@@ -1148,36 +1289,26 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1148
1289
|
},
|
|
1149
1290
|
addSprite(x, y, width, height, u0, v0, u1, v1, color = "#ffffff", alpha = 1, rotation = 0) {
|
|
1150
1291
|
if (!texture) return;
|
|
1151
|
-
const stride = FLOATS_PER_SPRITE_VERT *
|
|
1292
|
+
const stride = FLOATS_PER_SPRITE_VERT * VERTS_PER_QUAD;
|
|
1152
1293
|
spriteData = grow(spriteData, (spriteCount + 1) * stride);
|
|
1153
|
-
const
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
[
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
spriteData[o] = vx;
|
|
1172
|
-
spriteData[o + 1] = vy;
|
|
1173
|
-
spriteData[o + 2] = vu;
|
|
1174
|
-
spriteData[o + 3] = vv;
|
|
1175
|
-
spriteData[o + 4] = r;
|
|
1176
|
-
spriteData[o + 5] = g;
|
|
1177
|
-
spriteData[o + 6] = b;
|
|
1178
|
-
spriteData[o + 7] = al;
|
|
1179
|
-
o += FLOATS_PER_SPRITE_VERT;
|
|
1180
|
-
}
|
|
1294
|
+
const rgba = parseColorToRGBA(color);
|
|
1295
|
+
writeQuad(
|
|
1296
|
+
spriteData,
|
|
1297
|
+
spriteCount * stride,
|
|
1298
|
+
x,
|
|
1299
|
+
y,
|
|
1300
|
+
width,
|
|
1301
|
+
height,
|
|
1302
|
+
u0,
|
|
1303
|
+
v0,
|
|
1304
|
+
u1,
|
|
1305
|
+
v1,
|
|
1306
|
+
rgba[0],
|
|
1307
|
+
rgba[1],
|
|
1308
|
+
rgba[2],
|
|
1309
|
+
rgba[3] * alpha,
|
|
1310
|
+
rotation
|
|
1311
|
+
);
|
|
1181
1312
|
spriteCount++;
|
|
1182
1313
|
},
|
|
1183
1314
|
setMSDFTexture(source, range) {
|
|
@@ -1202,65 +1333,52 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1202
1333
|
},
|
|
1203
1334
|
addGlyph(x, y, width, height, u0, v0, u1, v1, color = "#ffffff", alpha = 1, rotation = 0) {
|
|
1204
1335
|
if (!msdfTexture) return;
|
|
1205
|
-
const stride = FLOATS_PER_SPRITE_VERT *
|
|
1336
|
+
const stride = FLOATS_PER_SPRITE_VERT * VERTS_PER_QUAD;
|
|
1206
1337
|
glyphData = grow(glyphData, (glyphCount + 1) * stride);
|
|
1207
|
-
const
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
[
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
glyphData[o] = vx;
|
|
1226
|
-
glyphData[o + 1] = vy;
|
|
1227
|
-
glyphData[o + 2] = vu;
|
|
1228
|
-
glyphData[o + 3] = vv;
|
|
1229
|
-
glyphData[o + 4] = r;
|
|
1230
|
-
glyphData[o + 5] = g;
|
|
1231
|
-
glyphData[o + 6] = b;
|
|
1232
|
-
glyphData[o + 7] = al;
|
|
1233
|
-
o += FLOATS_PER_SPRITE_VERT;
|
|
1234
|
-
}
|
|
1338
|
+
const rgba = parseColorToRGBA(color);
|
|
1339
|
+
writeQuad(
|
|
1340
|
+
glyphData,
|
|
1341
|
+
glyphCount * stride,
|
|
1342
|
+
x,
|
|
1343
|
+
y,
|
|
1344
|
+
width,
|
|
1345
|
+
height,
|
|
1346
|
+
u0,
|
|
1347
|
+
v0,
|
|
1348
|
+
u1,
|
|
1349
|
+
v1,
|
|
1350
|
+
rgba[0],
|
|
1351
|
+
rgba[1],
|
|
1352
|
+
rgba[2],
|
|
1353
|
+
rgba[3] * alpha,
|
|
1354
|
+
rotation
|
|
1355
|
+
);
|
|
1235
1356
|
glyphCount++;
|
|
1236
1357
|
},
|
|
1237
1358
|
addCircle(x, y, radius, color, alpha = 1) {
|
|
1238
1359
|
const needsQuad = logicalW > 0 && (x < radius || y < radius || x > logicalW - radius || y > logicalH - radius) || radius * 2 * dpr > maxPointSize;
|
|
1239
1360
|
if (needsQuad) {
|
|
1240
|
-
const stride = FLOATS_PER_SPRITE_VERT *
|
|
1361
|
+
const stride = FLOATS_PER_SPRITE_VERT * VERTS_PER_QUAD;
|
|
1241
1362
|
circleQuadData = grow(circleQuadData, (circleQuadCount + 1) * stride);
|
|
1242
|
-
const
|
|
1243
|
-
const
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
circleQuadData[o2 + 7] = al;
|
|
1262
|
-
o2 += FLOATS_PER_SPRITE_VERT;
|
|
1263
|
-
}
|
|
1363
|
+
const rgba = parseColorToRGBA(color);
|
|
1364
|
+
const d = radius * 2;
|
|
1365
|
+
writeQuad(
|
|
1366
|
+
circleQuadData,
|
|
1367
|
+
circleQuadCount * stride,
|
|
1368
|
+
x - radius,
|
|
1369
|
+
y - radius,
|
|
1370
|
+
d,
|
|
1371
|
+
d,
|
|
1372
|
+
0,
|
|
1373
|
+
0,
|
|
1374
|
+
1,
|
|
1375
|
+
1,
|
|
1376
|
+
rgba[0],
|
|
1377
|
+
rgba[1],
|
|
1378
|
+
rgba[2],
|
|
1379
|
+
rgba[3] * alpha,
|
|
1380
|
+
0
|
|
1381
|
+
);
|
|
1264
1382
|
circleQuadCount++;
|
|
1265
1383
|
return;
|
|
1266
1384
|
}
|
|
@@ -1277,42 +1395,34 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1277
1395
|
pointCount++;
|
|
1278
1396
|
},
|
|
1279
1397
|
addRect(x, y, width, height, color, alpha = 1, rotation = 0) {
|
|
1280
|
-
const stride = FLOATS_PER_RECT_VERT *
|
|
1398
|
+
const stride = FLOATS_PER_RECT_VERT * VERTS_PER_QUAD;
|
|
1281
1399
|
rectData = grow(rectData, (rectCount + 1) * stride);
|
|
1282
|
-
const
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
for (const [vx, vy] of verts) {
|
|
1297
|
-
rectData[o] = vx;
|
|
1298
|
-
rectData[o + 1] = vy;
|
|
1299
|
-
rectData[o + 2] = r;
|
|
1300
|
-
rectData[o + 3] = g;
|
|
1301
|
-
rectData[o + 4] = b;
|
|
1302
|
-
rectData[o + 5] = al;
|
|
1303
|
-
o += FLOATS_PER_RECT_VERT;
|
|
1304
|
-
}
|
|
1400
|
+
const rgba = parseColorToRGBA(color);
|
|
1401
|
+
writeRectQuad(
|
|
1402
|
+
rectData,
|
|
1403
|
+
rectCount * stride,
|
|
1404
|
+
x,
|
|
1405
|
+
y,
|
|
1406
|
+
width,
|
|
1407
|
+
height,
|
|
1408
|
+
rgba[0],
|
|
1409
|
+
rgba[1],
|
|
1410
|
+
rgba[2],
|
|
1411
|
+
rgba[3] * alpha,
|
|
1412
|
+
rotation
|
|
1413
|
+
);
|
|
1305
1414
|
rectCount++;
|
|
1306
1415
|
},
|
|
1307
1416
|
flush() {
|
|
1308
1417
|
if (rectCount > 0) {
|
|
1309
|
-
const floats = rectCount *
|
|
1418
|
+
const floats = rectCount * VERTS_PER_QUAD * FLOATS_PER_RECT_VERT;
|
|
1310
1419
|
gl.useProgram(rectProgram);
|
|
1311
1420
|
gl.bindVertexArray(rectVAO);
|
|
1312
1421
|
gl.bindBuffer(gl.ARRAY_BUFFER, rectBuffer);
|
|
1313
1422
|
gl.bufferData(gl.ARRAY_BUFFER, rectData.subarray(0, floats), gl.DYNAMIC_DRAW);
|
|
1314
1423
|
gl.uniform2f(rURes, logicalW, logicalH);
|
|
1315
|
-
|
|
1424
|
+
ensureQuadIndices(rectCount);
|
|
1425
|
+
gl.drawElements(gl.TRIANGLES, rectCount * INDICES_PER_QUAD, gl.UNSIGNED_INT, 0);
|
|
1316
1426
|
}
|
|
1317
1427
|
if (pointCount > 0) {
|
|
1318
1428
|
gl.useProgram(pointProgram);
|
|
@@ -1328,16 +1438,17 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1328
1438
|
gl.drawArrays(gl.POINTS, 0, pointCount);
|
|
1329
1439
|
}
|
|
1330
1440
|
if (circleQuadCount > 0) {
|
|
1331
|
-
const floats = circleQuadCount *
|
|
1441
|
+
const floats = circleQuadCount * VERTS_PER_QUAD * FLOATS_PER_SPRITE_VERT;
|
|
1332
1442
|
gl.useProgram(circleQuadProgram);
|
|
1333
1443
|
gl.bindVertexArray(circleQuadVAO);
|
|
1334
1444
|
gl.bindBuffer(gl.ARRAY_BUFFER, circleQuadBuffer);
|
|
1335
1445
|
gl.bufferData(gl.ARRAY_BUFFER, circleQuadData.subarray(0, floats), gl.DYNAMIC_DRAW);
|
|
1336
1446
|
gl.uniform2f(cURes, logicalW, logicalH);
|
|
1337
|
-
|
|
1447
|
+
ensureQuadIndices(circleQuadCount);
|
|
1448
|
+
gl.drawElements(gl.TRIANGLES, circleQuadCount * INDICES_PER_QUAD, gl.UNSIGNED_INT, 0);
|
|
1338
1449
|
}
|
|
1339
1450
|
if (spriteCount > 0 && texture) {
|
|
1340
|
-
const floats = spriteCount *
|
|
1451
|
+
const floats = spriteCount * VERTS_PER_QUAD * FLOATS_PER_SPRITE_VERT;
|
|
1341
1452
|
gl.useProgram(spriteProgram);
|
|
1342
1453
|
gl.bindVertexArray(spriteVAO);
|
|
1343
1454
|
gl.bindBuffer(gl.ARRAY_BUFFER, spriteBuffer);
|
|
@@ -1346,7 +1457,8 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1346
1457
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
1347
1458
|
gl.uniform1i(sUTex, 0);
|
|
1348
1459
|
gl.uniform2f(sURes, logicalW, logicalH);
|
|
1349
|
-
|
|
1460
|
+
ensureQuadIndices(spriteCount);
|
|
1461
|
+
gl.drawElements(gl.TRIANGLES, spriteCount * INDICES_PER_QUAD, gl.UNSIGNED_INT, 0);
|
|
1350
1462
|
}
|
|
1351
1463
|
gl.bindVertexArray(null);
|
|
1352
1464
|
drawGlyphs();
|
|
@@ -1359,6 +1471,7 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1359
1471
|
gl.deleteBuffer(spriteBuffer);
|
|
1360
1472
|
gl.deleteBuffer(glyphBuffer);
|
|
1361
1473
|
gl.deleteBuffer(circleQuadBuffer);
|
|
1474
|
+
gl.deleteBuffer(quadIndexBuffer);
|
|
1362
1475
|
gl.deleteVertexArray(pointVAO);
|
|
1363
1476
|
gl.deleteVertexArray(rectVAO);
|
|
1364
1477
|
gl.deleteVertexArray(spriteVAO);
|
|
@@ -825,8 +825,6 @@ function fromCanvas(css) {
|
|
|
825
825
|
function parseColorToRGBA(css) {
|
|
826
826
|
const hit = cache.get(css);
|
|
827
827
|
if (hit) {
|
|
828
|
-
cache.delete(css);
|
|
829
|
-
cache.set(css, hit);
|
|
830
828
|
return hit;
|
|
831
829
|
}
|
|
832
830
|
const trimmed = css.trim();
|
|
@@ -841,12 +839,26 @@ function parseColorToRGBA(css) {
|
|
|
841
839
|
// src/renderer/WebGLPointRenderer.ts
|
|
842
840
|
var FLOATS_PER_POINT = 7;
|
|
843
841
|
var POINT_STRIDE = FLOATS_PER_POINT * 4;
|
|
842
|
+
var VERTS_PER_QUAD = 4;
|
|
843
|
+
var INDICES_PER_QUAD = 6;
|
|
844
844
|
var FLOATS_PER_RECT_VERT = 6;
|
|
845
845
|
var RECT_VERT_STRIDE = FLOATS_PER_RECT_VERT * 4;
|
|
846
|
-
var VERTS_PER_RECT = 6;
|
|
847
846
|
var FLOATS_PER_SPRITE_VERT = 8;
|
|
848
847
|
var SPRITE_VERT_STRIDE = FLOATS_PER_SPRITE_VERT * 4;
|
|
849
|
-
|
|
848
|
+
function buildQuadIndices(quads) {
|
|
849
|
+
const out = new Uint32Array(quads * INDICES_PER_QUAD);
|
|
850
|
+
for (let i = 0; i < quads; i++) {
|
|
851
|
+
const v = i * VERTS_PER_QUAD;
|
|
852
|
+
const o = i * INDICES_PER_QUAD;
|
|
853
|
+
out[o] = v;
|
|
854
|
+
out[o + 1] = v + 1;
|
|
855
|
+
out[o + 2] = v + 2;
|
|
856
|
+
out[o + 3] = v;
|
|
857
|
+
out[o + 4] = v + 2;
|
|
858
|
+
out[o + 5] = v + 3;
|
|
859
|
+
}
|
|
860
|
+
return out;
|
|
861
|
+
}
|
|
850
862
|
var POINT_VERT = `#version 300 es
|
|
851
863
|
in vec2 a_pos;
|
|
852
864
|
in float a_radius;
|
|
@@ -974,6 +986,120 @@ function link(gl, vsSrc, fsSrc) {
|
|
|
974
986
|
}
|
|
975
987
|
return program;
|
|
976
988
|
}
|
|
989
|
+
function writeQuad(out, o, x, y, width, height, u0, v0, u1, v1, r, g, b, al, rotation) {
|
|
990
|
+
let x1;
|
|
991
|
+
let y1;
|
|
992
|
+
let x2;
|
|
993
|
+
let y2;
|
|
994
|
+
let x3;
|
|
995
|
+
let y3;
|
|
996
|
+
if (rotation === 0) {
|
|
997
|
+
x1 = x + width;
|
|
998
|
+
y1 = y;
|
|
999
|
+
x2 = x + width;
|
|
1000
|
+
y2 = y + height;
|
|
1001
|
+
x3 = x;
|
|
1002
|
+
y3 = y + height;
|
|
1003
|
+
} else {
|
|
1004
|
+
const s = Math.sin(rotation);
|
|
1005
|
+
const c = Math.cos(rotation);
|
|
1006
|
+
const wc = width * c;
|
|
1007
|
+
const ws = width * s;
|
|
1008
|
+
const hc = height * c;
|
|
1009
|
+
const hs = height * s;
|
|
1010
|
+
x1 = x + wc;
|
|
1011
|
+
y1 = y + ws;
|
|
1012
|
+
x2 = x + wc - hs;
|
|
1013
|
+
y2 = y + ws + hc;
|
|
1014
|
+
x3 = x - hs;
|
|
1015
|
+
y3 = y + hc;
|
|
1016
|
+
}
|
|
1017
|
+
out[o] = x;
|
|
1018
|
+
out[o + 1] = y;
|
|
1019
|
+
out[o + 2] = u0;
|
|
1020
|
+
out[o + 3] = v0;
|
|
1021
|
+
out[o + 4] = r;
|
|
1022
|
+
out[o + 5] = g;
|
|
1023
|
+
out[o + 6] = b;
|
|
1024
|
+
out[o + 7] = al;
|
|
1025
|
+
out[o + 8] = x1;
|
|
1026
|
+
out[o + 9] = y1;
|
|
1027
|
+
out[o + 10] = u1;
|
|
1028
|
+
out[o + 11] = v0;
|
|
1029
|
+
out[o + 12] = r;
|
|
1030
|
+
out[o + 13] = g;
|
|
1031
|
+
out[o + 14] = b;
|
|
1032
|
+
out[o + 15] = al;
|
|
1033
|
+
out[o + 16] = x2;
|
|
1034
|
+
out[o + 17] = y2;
|
|
1035
|
+
out[o + 18] = u1;
|
|
1036
|
+
out[o + 19] = v1;
|
|
1037
|
+
out[o + 20] = r;
|
|
1038
|
+
out[o + 21] = g;
|
|
1039
|
+
out[o + 22] = b;
|
|
1040
|
+
out[o + 23] = al;
|
|
1041
|
+
out[o + 24] = x3;
|
|
1042
|
+
out[o + 25] = y3;
|
|
1043
|
+
out[o + 26] = u0;
|
|
1044
|
+
out[o + 27] = v1;
|
|
1045
|
+
out[o + 28] = r;
|
|
1046
|
+
out[o + 29] = g;
|
|
1047
|
+
out[o + 30] = b;
|
|
1048
|
+
out[o + 31] = al;
|
|
1049
|
+
}
|
|
1050
|
+
function writeRectQuad(out, o, x, y, width, height, r, g, b, al, rotation) {
|
|
1051
|
+
let x1;
|
|
1052
|
+
let y1;
|
|
1053
|
+
let x2;
|
|
1054
|
+
let y2;
|
|
1055
|
+
let x3;
|
|
1056
|
+
let y3;
|
|
1057
|
+
if (rotation === 0) {
|
|
1058
|
+
x1 = x + width;
|
|
1059
|
+
y1 = y;
|
|
1060
|
+
x2 = x + width;
|
|
1061
|
+
y2 = y + height;
|
|
1062
|
+
x3 = x;
|
|
1063
|
+
y3 = y + height;
|
|
1064
|
+
} else {
|
|
1065
|
+
const s = Math.sin(rotation);
|
|
1066
|
+
const c = Math.cos(rotation);
|
|
1067
|
+
const wc = width * c;
|
|
1068
|
+
const ws = width * s;
|
|
1069
|
+
const hc = height * c;
|
|
1070
|
+
const hs = height * s;
|
|
1071
|
+
x1 = x + wc;
|
|
1072
|
+
y1 = y + ws;
|
|
1073
|
+
x2 = x + wc - hs;
|
|
1074
|
+
y2 = y + ws + hc;
|
|
1075
|
+
x3 = x - hs;
|
|
1076
|
+
y3 = y + hc;
|
|
1077
|
+
}
|
|
1078
|
+
out[o] = x;
|
|
1079
|
+
out[o + 1] = y;
|
|
1080
|
+
out[o + 2] = r;
|
|
1081
|
+
out[o + 3] = g;
|
|
1082
|
+
out[o + 4] = b;
|
|
1083
|
+
out[o + 5] = al;
|
|
1084
|
+
out[o + 6] = x1;
|
|
1085
|
+
out[o + 7] = y1;
|
|
1086
|
+
out[o + 8] = r;
|
|
1087
|
+
out[o + 9] = g;
|
|
1088
|
+
out[o + 10] = b;
|
|
1089
|
+
out[o + 11] = al;
|
|
1090
|
+
out[o + 12] = x2;
|
|
1091
|
+
out[o + 13] = y2;
|
|
1092
|
+
out[o + 14] = r;
|
|
1093
|
+
out[o + 15] = g;
|
|
1094
|
+
out[o + 16] = b;
|
|
1095
|
+
out[o + 17] = al;
|
|
1096
|
+
out[o + 18] = x3;
|
|
1097
|
+
out[o + 19] = y3;
|
|
1098
|
+
out[o + 20] = r;
|
|
1099
|
+
out[o + 21] = g;
|
|
1100
|
+
out[o + 22] = b;
|
|
1101
|
+
out[o + 23] = al;
|
|
1102
|
+
}
|
|
977
1103
|
function grow(data, needed) {
|
|
978
1104
|
if (needed <= data.length) return data;
|
|
979
1105
|
let cap = data.length;
|
|
@@ -1068,6 +1194,22 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1068
1194
|
gl.enableVertexAttribArray(cATint);
|
|
1069
1195
|
gl.vertexAttribPointer(cATint, 4, gl.FLOAT, false, SPRITE_VERT_STRIDE, 16);
|
|
1070
1196
|
gl.bindVertexArray(null);
|
|
1197
|
+
const quadIndexBuffer = gl.createBuffer();
|
|
1198
|
+
let quadIndexCapacity = 0;
|
|
1199
|
+
const ensureQuadIndices = (quads) => {
|
|
1200
|
+
if (quads <= quadIndexCapacity) return;
|
|
1201
|
+
let cap = quadIndexCapacity || 256;
|
|
1202
|
+
while (cap < quads) cap *= 2;
|
|
1203
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, quadIndexBuffer);
|
|
1204
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, buildQuadIndices(cap), gl.STATIC_DRAW);
|
|
1205
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
|
|
1206
|
+
quadIndexCapacity = cap;
|
|
1207
|
+
};
|
|
1208
|
+
for (const vao of [rectVAO, spriteVAO, glyphVAO, circleQuadVAO]) {
|
|
1209
|
+
gl.bindVertexArray(vao);
|
|
1210
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, quadIndexBuffer);
|
|
1211
|
+
gl.bindVertexArray(null);
|
|
1212
|
+
}
|
|
1071
1213
|
let texture = null;
|
|
1072
1214
|
let textureSource = null;
|
|
1073
1215
|
let msdfTexture = null;
|
|
@@ -1075,15 +1217,13 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1075
1217
|
let distanceRange = 4;
|
|
1076
1218
|
let pointData = new Float32Array(FLOATS_PER_POINT * 1024);
|
|
1077
1219
|
let pointCount = 0;
|
|
1078
|
-
let rectData = new Float32Array(FLOATS_PER_RECT_VERT *
|
|
1220
|
+
let rectData = new Float32Array(FLOATS_PER_RECT_VERT * VERTS_PER_QUAD * 256);
|
|
1079
1221
|
let rectCount = 0;
|
|
1080
|
-
let spriteData = new Float32Array(FLOATS_PER_SPRITE_VERT *
|
|
1222
|
+
let spriteData = new Float32Array(FLOATS_PER_SPRITE_VERT * VERTS_PER_QUAD * 256);
|
|
1081
1223
|
let spriteCount = 0;
|
|
1082
|
-
let glyphData = new Float32Array(FLOATS_PER_SPRITE_VERT *
|
|
1224
|
+
let glyphData = new Float32Array(FLOATS_PER_SPRITE_VERT * VERTS_PER_QUAD * 1024);
|
|
1083
1225
|
let glyphCount = 0;
|
|
1084
|
-
let circleQuadData = new Float32Array(
|
|
1085
|
-
FLOATS_PER_SPRITE_VERT * VERTS_PER_SPRITE * 64
|
|
1086
|
-
);
|
|
1226
|
+
let circleQuadData = new Float32Array(FLOATS_PER_SPRITE_VERT * VERTS_PER_QUAD * 64);
|
|
1087
1227
|
let circleQuadCount = 0;
|
|
1088
1228
|
let logicalW = 0;
|
|
1089
1229
|
let logicalH = 0;
|
|
@@ -1093,7 +1233,7 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1093
1233
|
const maxPointSize = pointSizeRange ? pointSizeRange[1] : Infinity;
|
|
1094
1234
|
const drawGlyphs = () => {
|
|
1095
1235
|
if (glyphCount === 0 || !msdfTexture) return;
|
|
1096
|
-
const floats = glyphCount *
|
|
1236
|
+
const floats = glyphCount * VERTS_PER_QUAD * FLOATS_PER_SPRITE_VERT;
|
|
1097
1237
|
gl.useProgram(msdfProgram);
|
|
1098
1238
|
gl.bindVertexArray(glyphVAO);
|
|
1099
1239
|
gl.bindBuffer(gl.ARRAY_BUFFER, glyphBuffer);
|
|
@@ -1103,7 +1243,8 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1103
1243
|
gl.uniform1i(gUTex, 0);
|
|
1104
1244
|
gl.uniform2f(gURes, logicalW, logicalH);
|
|
1105
1245
|
gl.uniform1f(gURange, distanceRange);
|
|
1106
|
-
|
|
1246
|
+
ensureQuadIndices(glyphCount);
|
|
1247
|
+
gl.drawElements(gl.TRIANGLES, glyphCount * INDICES_PER_QUAD, gl.UNSIGNED_INT, 0);
|
|
1107
1248
|
gl.bindVertexArray(null);
|
|
1108
1249
|
glyphCount = 0;
|
|
1109
1250
|
};
|
|
@@ -1146,36 +1287,26 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1146
1287
|
},
|
|
1147
1288
|
addSprite(x, y, width, height, u0, v0, u1, v1, color = "#ffffff", alpha = 1, rotation = 0) {
|
|
1148
1289
|
if (!texture) return;
|
|
1149
|
-
const stride = FLOATS_PER_SPRITE_VERT *
|
|
1290
|
+
const stride = FLOATS_PER_SPRITE_VERT * VERTS_PER_QUAD;
|
|
1150
1291
|
spriteData = grow(spriteData, (spriteCount + 1) * stride);
|
|
1151
|
-
const
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
[
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
spriteData[o] = vx;
|
|
1170
|
-
spriteData[o + 1] = vy;
|
|
1171
|
-
spriteData[o + 2] = vu;
|
|
1172
|
-
spriteData[o + 3] = vv;
|
|
1173
|
-
spriteData[o + 4] = r;
|
|
1174
|
-
spriteData[o + 5] = g;
|
|
1175
|
-
spriteData[o + 6] = b;
|
|
1176
|
-
spriteData[o + 7] = al;
|
|
1177
|
-
o += FLOATS_PER_SPRITE_VERT;
|
|
1178
|
-
}
|
|
1292
|
+
const rgba = parseColorToRGBA(color);
|
|
1293
|
+
writeQuad(
|
|
1294
|
+
spriteData,
|
|
1295
|
+
spriteCount * stride,
|
|
1296
|
+
x,
|
|
1297
|
+
y,
|
|
1298
|
+
width,
|
|
1299
|
+
height,
|
|
1300
|
+
u0,
|
|
1301
|
+
v0,
|
|
1302
|
+
u1,
|
|
1303
|
+
v1,
|
|
1304
|
+
rgba[0],
|
|
1305
|
+
rgba[1],
|
|
1306
|
+
rgba[2],
|
|
1307
|
+
rgba[3] * alpha,
|
|
1308
|
+
rotation
|
|
1309
|
+
);
|
|
1179
1310
|
spriteCount++;
|
|
1180
1311
|
},
|
|
1181
1312
|
setMSDFTexture(source, range) {
|
|
@@ -1200,65 +1331,52 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1200
1331
|
},
|
|
1201
1332
|
addGlyph(x, y, width, height, u0, v0, u1, v1, color = "#ffffff", alpha = 1, rotation = 0) {
|
|
1202
1333
|
if (!msdfTexture) return;
|
|
1203
|
-
const stride = FLOATS_PER_SPRITE_VERT *
|
|
1334
|
+
const stride = FLOATS_PER_SPRITE_VERT * VERTS_PER_QUAD;
|
|
1204
1335
|
glyphData = grow(glyphData, (glyphCount + 1) * stride);
|
|
1205
|
-
const
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
[
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
glyphData[o] = vx;
|
|
1224
|
-
glyphData[o + 1] = vy;
|
|
1225
|
-
glyphData[o + 2] = vu;
|
|
1226
|
-
glyphData[o + 3] = vv;
|
|
1227
|
-
glyphData[o + 4] = r;
|
|
1228
|
-
glyphData[o + 5] = g;
|
|
1229
|
-
glyphData[o + 6] = b;
|
|
1230
|
-
glyphData[o + 7] = al;
|
|
1231
|
-
o += FLOATS_PER_SPRITE_VERT;
|
|
1232
|
-
}
|
|
1336
|
+
const rgba = parseColorToRGBA(color);
|
|
1337
|
+
writeQuad(
|
|
1338
|
+
glyphData,
|
|
1339
|
+
glyphCount * stride,
|
|
1340
|
+
x,
|
|
1341
|
+
y,
|
|
1342
|
+
width,
|
|
1343
|
+
height,
|
|
1344
|
+
u0,
|
|
1345
|
+
v0,
|
|
1346
|
+
u1,
|
|
1347
|
+
v1,
|
|
1348
|
+
rgba[0],
|
|
1349
|
+
rgba[1],
|
|
1350
|
+
rgba[2],
|
|
1351
|
+
rgba[3] * alpha,
|
|
1352
|
+
rotation
|
|
1353
|
+
);
|
|
1233
1354
|
glyphCount++;
|
|
1234
1355
|
},
|
|
1235
1356
|
addCircle(x, y, radius, color, alpha = 1) {
|
|
1236
1357
|
const needsQuad = logicalW > 0 && (x < radius || y < radius || x > logicalW - radius || y > logicalH - radius) || radius * 2 * dpr > maxPointSize;
|
|
1237
1358
|
if (needsQuad) {
|
|
1238
|
-
const stride = FLOATS_PER_SPRITE_VERT *
|
|
1359
|
+
const stride = FLOATS_PER_SPRITE_VERT * VERTS_PER_QUAD;
|
|
1239
1360
|
circleQuadData = grow(circleQuadData, (circleQuadCount + 1) * stride);
|
|
1240
|
-
const
|
|
1241
|
-
const
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
circleQuadData[o2 + 7] = al;
|
|
1260
|
-
o2 += FLOATS_PER_SPRITE_VERT;
|
|
1261
|
-
}
|
|
1361
|
+
const rgba = parseColorToRGBA(color);
|
|
1362
|
+
const d = radius * 2;
|
|
1363
|
+
writeQuad(
|
|
1364
|
+
circleQuadData,
|
|
1365
|
+
circleQuadCount * stride,
|
|
1366
|
+
x - radius,
|
|
1367
|
+
y - radius,
|
|
1368
|
+
d,
|
|
1369
|
+
d,
|
|
1370
|
+
0,
|
|
1371
|
+
0,
|
|
1372
|
+
1,
|
|
1373
|
+
1,
|
|
1374
|
+
rgba[0],
|
|
1375
|
+
rgba[1],
|
|
1376
|
+
rgba[2],
|
|
1377
|
+
rgba[3] * alpha,
|
|
1378
|
+
0
|
|
1379
|
+
);
|
|
1262
1380
|
circleQuadCount++;
|
|
1263
1381
|
return;
|
|
1264
1382
|
}
|
|
@@ -1275,42 +1393,34 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1275
1393
|
pointCount++;
|
|
1276
1394
|
},
|
|
1277
1395
|
addRect(x, y, width, height, color, alpha = 1, rotation = 0) {
|
|
1278
|
-
const stride = FLOATS_PER_RECT_VERT *
|
|
1396
|
+
const stride = FLOATS_PER_RECT_VERT * VERTS_PER_QUAD;
|
|
1279
1397
|
rectData = grow(rectData, (rectCount + 1) * stride);
|
|
1280
|
-
const
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
for (const [vx, vy] of verts) {
|
|
1295
|
-
rectData[o] = vx;
|
|
1296
|
-
rectData[o + 1] = vy;
|
|
1297
|
-
rectData[o + 2] = r;
|
|
1298
|
-
rectData[o + 3] = g;
|
|
1299
|
-
rectData[o + 4] = b;
|
|
1300
|
-
rectData[o + 5] = al;
|
|
1301
|
-
o += FLOATS_PER_RECT_VERT;
|
|
1302
|
-
}
|
|
1398
|
+
const rgba = parseColorToRGBA(color);
|
|
1399
|
+
writeRectQuad(
|
|
1400
|
+
rectData,
|
|
1401
|
+
rectCount * stride,
|
|
1402
|
+
x,
|
|
1403
|
+
y,
|
|
1404
|
+
width,
|
|
1405
|
+
height,
|
|
1406
|
+
rgba[0],
|
|
1407
|
+
rgba[1],
|
|
1408
|
+
rgba[2],
|
|
1409
|
+
rgba[3] * alpha,
|
|
1410
|
+
rotation
|
|
1411
|
+
);
|
|
1303
1412
|
rectCount++;
|
|
1304
1413
|
},
|
|
1305
1414
|
flush() {
|
|
1306
1415
|
if (rectCount > 0) {
|
|
1307
|
-
const floats = rectCount *
|
|
1416
|
+
const floats = rectCount * VERTS_PER_QUAD * FLOATS_PER_RECT_VERT;
|
|
1308
1417
|
gl.useProgram(rectProgram);
|
|
1309
1418
|
gl.bindVertexArray(rectVAO);
|
|
1310
1419
|
gl.bindBuffer(gl.ARRAY_BUFFER, rectBuffer);
|
|
1311
1420
|
gl.bufferData(gl.ARRAY_BUFFER, rectData.subarray(0, floats), gl.DYNAMIC_DRAW);
|
|
1312
1421
|
gl.uniform2f(rURes, logicalW, logicalH);
|
|
1313
|
-
|
|
1422
|
+
ensureQuadIndices(rectCount);
|
|
1423
|
+
gl.drawElements(gl.TRIANGLES, rectCount * INDICES_PER_QUAD, gl.UNSIGNED_INT, 0);
|
|
1314
1424
|
}
|
|
1315
1425
|
if (pointCount > 0) {
|
|
1316
1426
|
gl.useProgram(pointProgram);
|
|
@@ -1326,16 +1436,17 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1326
1436
|
gl.drawArrays(gl.POINTS, 0, pointCount);
|
|
1327
1437
|
}
|
|
1328
1438
|
if (circleQuadCount > 0) {
|
|
1329
|
-
const floats = circleQuadCount *
|
|
1439
|
+
const floats = circleQuadCount * VERTS_PER_QUAD * FLOATS_PER_SPRITE_VERT;
|
|
1330
1440
|
gl.useProgram(circleQuadProgram);
|
|
1331
1441
|
gl.bindVertexArray(circleQuadVAO);
|
|
1332
1442
|
gl.bindBuffer(gl.ARRAY_BUFFER, circleQuadBuffer);
|
|
1333
1443
|
gl.bufferData(gl.ARRAY_BUFFER, circleQuadData.subarray(0, floats), gl.DYNAMIC_DRAW);
|
|
1334
1444
|
gl.uniform2f(cURes, logicalW, logicalH);
|
|
1335
|
-
|
|
1445
|
+
ensureQuadIndices(circleQuadCount);
|
|
1446
|
+
gl.drawElements(gl.TRIANGLES, circleQuadCount * INDICES_PER_QUAD, gl.UNSIGNED_INT, 0);
|
|
1336
1447
|
}
|
|
1337
1448
|
if (spriteCount > 0 && texture) {
|
|
1338
|
-
const floats = spriteCount *
|
|
1449
|
+
const floats = spriteCount * VERTS_PER_QUAD * FLOATS_PER_SPRITE_VERT;
|
|
1339
1450
|
gl.useProgram(spriteProgram);
|
|
1340
1451
|
gl.bindVertexArray(spriteVAO);
|
|
1341
1452
|
gl.bindBuffer(gl.ARRAY_BUFFER, spriteBuffer);
|
|
@@ -1344,7 +1455,8 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1344
1455
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
1345
1456
|
gl.uniform1i(sUTex, 0);
|
|
1346
1457
|
gl.uniform2f(sURes, logicalW, logicalH);
|
|
1347
|
-
|
|
1458
|
+
ensureQuadIndices(spriteCount);
|
|
1459
|
+
gl.drawElements(gl.TRIANGLES, spriteCount * INDICES_PER_QUAD, gl.UNSIGNED_INT, 0);
|
|
1348
1460
|
}
|
|
1349
1461
|
gl.bindVertexArray(null);
|
|
1350
1462
|
drawGlyphs();
|
|
@@ -1357,6 +1469,7 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1357
1469
|
gl.deleteBuffer(spriteBuffer);
|
|
1358
1470
|
gl.deleteBuffer(glyphBuffer);
|
|
1359
1471
|
gl.deleteBuffer(circleQuadBuffer);
|
|
1472
|
+
gl.deleteBuffer(quadIndexBuffer);
|
|
1360
1473
|
gl.deleteVertexArray(pointVAO);
|
|
1361
1474
|
gl.deleteVertexArray(rectVAO);
|
|
1362
1475
|
gl.deleteVertexArray(spriteVAO);
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
var
|
|
11
|
+
var _chunkL4SWVP2Hjs = require('./chunk-L4SWVP2H.js');
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
|
|
@@ -2162,17 +2162,17 @@ var Scene = (_class6 = class _Scene {
|
|
|
2162
2162
|
this._devFrameCount++;
|
|
2163
2163
|
if (this._devFrameCount % 120 !== 0) return;
|
|
2164
2164
|
if (this.a11yElements) {
|
|
2165
|
-
let
|
|
2165
|
+
let projectableCount = 0;
|
|
2166
2166
|
const walk = (node) => {
|
|
2167
|
-
if (
|
|
2167
|
+
if (this.shouldProjectA11y(node)) projectableCount++;
|
|
2168
2168
|
for (const c of node.children) walk(c);
|
|
2169
2169
|
};
|
|
2170
2170
|
walk(this.root);
|
|
2171
2171
|
for (const c of this.overlayRoot.children) walk(c);
|
|
2172
2172
|
const shadowCount = this.a11yElements.size;
|
|
2173
|
-
if (shadowCount >
|
|
2173
|
+
if (shadowCount > projectableCount) {
|
|
2174
2174
|
this._devWarn(
|
|
2175
|
-
`a11yElements (${shadowCount}) exceeds
|
|
2175
|
+
`a11yElements (${shadowCount}) exceeds projectable entities (${projectableCount}). Call scene.detachA11y(entity) before removing interactive children from the tree, or their shadow nodes leak.`
|
|
2176
2176
|
);
|
|
2177
2177
|
}
|
|
2178
2178
|
}
|
|
@@ -2247,7 +2247,7 @@ var Scene = (_class6 = class _Scene {
|
|
|
2247
2247
|
if (options.renderer) {
|
|
2248
2248
|
this.renderer = options.renderer;
|
|
2249
2249
|
} else {
|
|
2250
|
-
this.renderer = new (0,
|
|
2250
|
+
this.renderer = new (0, _chunkL4SWVP2Hjs.CanvasRenderer)(
|
|
2251
2251
|
canvas,
|
|
2252
2252
|
this.disableWindowResize ? { width: this.width, height: this.height } : void 0,
|
|
2253
2253
|
this.maxDPR
|
|
@@ -2643,7 +2643,19 @@ var Scene = (_class6 = class _Scene {
|
|
|
2643
2643
|
* without removing it from the scene graph. Components that manage dynamic
|
|
2644
2644
|
* interactive *child* entities (e.g. a {@link Entity}'s per-link hotspots) call
|
|
2645
2645
|
* this before discarding those children so their shadow `<a>`/controls don't
|
|
2646
|
-
* leak
|
|
2646
|
+
* leak.
|
|
2647
|
+
*
|
|
2648
|
+
* `syncA11y` itself only creates and updates, never prunes — but it is always
|
|
2649
|
+
* followed by `enforceA11yDomOrder`, whose prune pass removes any element
|
|
2650
|
+
* whose entity is no longer reachable in the tree or no longer satisfies
|
|
2651
|
+
* {@link shouldProjectA11y}. So an entity that is `remove()`d, or whose
|
|
2652
|
+
* `interactive` flips to `false`, has its element torn down on the next synced
|
|
2653
|
+
* frame without any explicit call.
|
|
2654
|
+
*
|
|
2655
|
+
* This method is for the case that pass cannot see: a child dropped from a
|
|
2656
|
+
* component's own bookkeeping while still parented, or one discarded before
|
|
2657
|
+
* the next sync runs. Calling it is always safe and is the right habit for
|
|
2658
|
+
* pooled children.
|
|
2647
2659
|
*
|
|
2648
2660
|
* @param entity - The subtree whose shadow nodes should be removed.
|
|
2649
2661
|
*/
|
|
@@ -2932,12 +2944,34 @@ var Scene = (_class6 = class _Scene {
|
|
|
2932
2944
|
}
|
|
2933
2945
|
if (element.getAttribute(name) !== value) element.setAttribute(name, value);
|
|
2934
2946
|
}
|
|
2947
|
+
/**
|
|
2948
|
+
* Whether `node` should have an a11y shadow element projected for it.
|
|
2949
|
+
*
|
|
2950
|
+
* The single authority for that decision. It was previously inlined verbatim
|
|
2951
|
+
* at four call sites — `syncA11y` (create/update), `enforceA11yDomOrder`
|
|
2952
|
+
* (which ids survive pruning), `getA11yTree` (the public snapshot) and
|
|
2953
|
+
* `render` (z-index / reading-order assignment). Four copies of one predicate
|
|
2954
|
+
* is a standing correctness hazard: if any of them drifts, elements either
|
|
2955
|
+
* leak (created but never marked active, so pruned every frame and rebuilt) or
|
|
2956
|
+
* go missing from the semantic tree while still present in the DOM.
|
|
2957
|
+
*
|
|
2958
|
+
* A box is required because a zero-size element is unfocusable and
|
|
2959
|
+
* unhittable; `a11yFullViewport` is the deliberate exception, since those
|
|
2960
|
+
* nodes are boundless interaction surfaces mounted behind everything else.
|
|
2961
|
+
*
|
|
2962
|
+
* Keep this the only place the rule is written. A planned per-entity
|
|
2963
|
+
* `a11yProjection` mode ('eager' | 'onDemand' | 'never') extends exactly this
|
|
2964
|
+
* predicate, which is only tractable while it has one home.
|
|
2965
|
+
*/
|
|
2966
|
+
shouldProjectA11y(node) {
|
|
2967
|
+
return node.interactive && (node.width > 0 || node.a11yFullViewport);
|
|
2968
|
+
}
|
|
2935
2969
|
syncA11y(node) {
|
|
2936
2970
|
if (!this.a11yRoot) return;
|
|
2937
2971
|
if (node.isDOMPortal) {
|
|
2938
2972
|
return;
|
|
2939
2973
|
}
|
|
2940
|
-
if (
|
|
2974
|
+
if (this.shouldProjectA11y(node)) {
|
|
2941
2975
|
let el = this.a11yElements.get(node.id);
|
|
2942
2976
|
const attrs = node.getA11yAttributes();
|
|
2943
2977
|
const expectedTag = attrs.tag || "div";
|
|
@@ -3136,7 +3170,7 @@ var Scene = (_class6 = class _Scene {
|
|
|
3136
3170
|
this.syncOptionalAttribute(
|
|
3137
3171
|
el,
|
|
3138
3172
|
"href",
|
|
3139
|
-
attrs.href === void 0 ? void 0 :
|
|
3173
|
+
attrs.href === void 0 ? void 0 : _chunkL4SWVP2Hjs.sanitizeUrl.call(void 0, attrs.href)
|
|
3140
3174
|
);
|
|
3141
3175
|
this.syncOptionalAttribute(el, "target", attrs.target);
|
|
3142
3176
|
}
|
|
@@ -3713,7 +3747,7 @@ var Scene = (_class6 = class _Scene {
|
|
|
3713
3747
|
if (node.a11yFullViewport) this.fullViewportElements.push(contentEl);
|
|
3714
3748
|
else this.normalElements.push(contentEl);
|
|
3715
3749
|
}
|
|
3716
|
-
if (
|
|
3750
|
+
if (this.shouldProjectA11y(node)) {
|
|
3717
3751
|
const el = this.a11yElements.get(node.id);
|
|
3718
3752
|
if (el) {
|
|
3719
3753
|
this.activeIds.add(node.id);
|
|
@@ -3852,7 +3886,7 @@ var Scene = (_class6 = class _Scene {
|
|
|
3852
3886
|
const traverse = (node, parentNode) => {
|
|
3853
3887
|
if (node.isDOMPortal) return;
|
|
3854
3888
|
let currentA11yNode = null;
|
|
3855
|
-
if (
|
|
3889
|
+
if (this.shouldProjectA11y(node)) {
|
|
3856
3890
|
const el = this.a11yElements.get(node.id);
|
|
3857
3891
|
if (el) {
|
|
3858
3892
|
const attrs = node.getA11yAttributes();
|
|
@@ -4222,7 +4256,7 @@ var Scene = (_class6 = class _Scene {
|
|
|
4222
4256
|
const orthogonalTolerance = Math.max(1, worldScaleX * worldScaleY) * 1e-6;
|
|
4223
4257
|
const isSimilarityTransform = Number.isFinite(worldScaleX) && Number.isFinite(worldScaleY) && Math.abs(worldScaleX - worldScaleY) <= scaleTolerance && Math.abs(a * c + b * d) <= orthogonalTolerance;
|
|
4224
4258
|
const a11yEl = isMainRenderer ? this.a11yElements.get(node.id) : void 0;
|
|
4225
|
-
const willProjectA11y = isMainRenderer &&
|
|
4259
|
+
const willProjectA11y = isMainRenderer && this.shouldProjectA11y(node);
|
|
4226
4260
|
if (a11yEl || willProjectA11y) {
|
|
4227
4261
|
const renderOrder = this.renderOrderCounter++;
|
|
4228
4262
|
if (willProjectA11y) this.a11yRenderOrders.set(node.id, renderOrder);
|
|
@@ -4344,7 +4378,7 @@ var Scene = (_class6 = class _Scene {
|
|
|
4344
4378
|
* Export the current scene state to a lightweight, flat SVG XML string.
|
|
4345
4379
|
*/
|
|
4346
4380
|
toSVG() {
|
|
4347
|
-
const renderer = new (0,
|
|
4381
|
+
const renderer = new (0, _chunkL4SWVP2Hjs.SVGRenderer)(this.width, this.height);
|
|
4348
4382
|
this.render(renderer, 0, 0);
|
|
4349
4383
|
return renderer.toXMLString();
|
|
4350
4384
|
}
|
|
@@ -5370,8 +5404,8 @@ var DOMPortalEntity = (_class10 = class extends _chunkDUYB4GX4js.Entity {
|
|
|
5370
5404
|
}, _class10);
|
|
5371
5405
|
|
|
5372
5406
|
// src/index.ts
|
|
5373
|
-
Scene.registerWebGLPointRendererCreator(
|
|
5374
|
-
Scene.registerWebGPUParticleSystemManager(
|
|
5407
|
+
Scene.registerWebGLPointRendererCreator(_chunkL4SWVP2Hjs.createWebGLPointRenderer);
|
|
5408
|
+
Scene.registerWebGPUParticleSystemManager(_chunkL4SWVP2Hjs.WebGPUParticleSystemManager);
|
|
5375
5409
|
|
|
5376
5410
|
|
|
5377
5411
|
|
|
@@ -5406,4 +5440,4 @@ Scene.registerWebGPUParticleSystemManager(_chunkIYPLG4Z4js.WebGPUParticleSystemM
|
|
|
5406
5440
|
|
|
5407
5441
|
|
|
5408
5442
|
|
|
5409
|
-
exports.CanvasRenderer =
|
|
5443
|
+
exports.CanvasRenderer = _chunkL4SWVP2Hjs.CanvasRenderer; exports.Circle = Circle; exports.ComputeParticleEntity = ComputeParticleEntity; exports.DOMPortalEntity = DOMPortalEntity; exports.Entity = _chunkDUYB4GX4js.Entity; exports.GridTextEntity = GridTextEntity; exports.Group = Group; exports.MSDFTextEntity = _chunkDUYB4GX4js.MSDFTextEntity; exports.PARTICLE_OFFSET_LIFE = PARTICLE_OFFSET_LIFE; exports.PARTICLE_OFFSET_ORIGIN_X = PARTICLE_OFFSET_ORIGIN_X; exports.PARTICLE_OFFSET_ORIGIN_Y = PARTICLE_OFFSET_ORIGIN_Y; exports.PARTICLE_OFFSET_POSITION_X = PARTICLE_OFFSET_POSITION_X; exports.PARTICLE_OFFSET_POSITION_Y = PARTICLE_OFFSET_POSITION_Y; exports.PARTICLE_OFFSET_SIZE = PARTICLE_OFFSET_SIZE; exports.PARTICLE_OFFSET_VELOCITY_X = PARTICLE_OFFSET_VELOCITY_X; exports.PARTICLE_OFFSET_VELOCITY_Y = PARTICLE_OFFSET_VELOCITY_Y; exports.PARTICLE_STRIDE_FLOATS = PARTICLE_STRIDE_FLOATS; exports.REDUCED_MOTION_FPS = REDUCED_MOTION_FPS; exports.Rect = Rect; exports.SVGEntity = _chunkDUYB4GX4js.SVGEntity; exports.SVGRenderer = _chunkL4SWVP2Hjs.SVGRenderer; exports.Scene = Scene; exports.SplineEntity = SplineEntity; exports.TextEntity = TextEntity; exports.TextRasterCache = _chunkL4SWVP2Hjs.TextRasterCache; exports.VectoJSEvent = _chunkDUYB4GX4js.VectoJSEvent; exports.WebGPUParticleSystemManager = _chunkL4SWVP2Hjs.WebGPUParticleSystemManager; exports.createWebGLPointRenderer = _chunkL4SWVP2Hjs.createWebGLPointRenderer; exports.isSafeUrl = _chunkL4SWVP2Hjs.isSafeUrl; exports.loadSpline = loadSpline; exports.parseColorToRGBA = _chunkL4SWVP2Hjs.parseColorToRGBA; exports.polySegmentToBezier = polySegmentToBezier; exports.sanitizeUrl = _chunkL4SWVP2Hjs.sanitizeUrl;
|
package/dist/index.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
isSafeUrl,
|
|
8
8
|
parseColorToRGBA,
|
|
9
9
|
sanitizeUrl
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-QS3CUV7H.mjs";
|
|
11
11
|
import {
|
|
12
12
|
Entity,
|
|
13
13
|
MSDFTextEntity,
|
|
@@ -2161,17 +2161,17 @@ var Scene = class _Scene {
|
|
|
2161
2161
|
this._devFrameCount++;
|
|
2162
2162
|
if (this._devFrameCount % 120 !== 0) return;
|
|
2163
2163
|
if (this.a11yElements) {
|
|
2164
|
-
let
|
|
2164
|
+
let projectableCount = 0;
|
|
2165
2165
|
const walk = (node) => {
|
|
2166
|
-
if (
|
|
2166
|
+
if (this.shouldProjectA11y(node)) projectableCount++;
|
|
2167
2167
|
for (const c of node.children) walk(c);
|
|
2168
2168
|
};
|
|
2169
2169
|
walk(this.root);
|
|
2170
2170
|
for (const c of this.overlayRoot.children) walk(c);
|
|
2171
2171
|
const shadowCount = this.a11yElements.size;
|
|
2172
|
-
if (shadowCount >
|
|
2172
|
+
if (shadowCount > projectableCount) {
|
|
2173
2173
|
this._devWarn(
|
|
2174
|
-
`a11yElements (${shadowCount}) exceeds
|
|
2174
|
+
`a11yElements (${shadowCount}) exceeds projectable entities (${projectableCount}). Call scene.detachA11y(entity) before removing interactive children from the tree, or their shadow nodes leak.`
|
|
2175
2175
|
);
|
|
2176
2176
|
}
|
|
2177
2177
|
}
|
|
@@ -2642,7 +2642,19 @@ var Scene = class _Scene {
|
|
|
2642
2642
|
* without removing it from the scene graph. Components that manage dynamic
|
|
2643
2643
|
* interactive *child* entities (e.g. a {@link Entity}'s per-link hotspots) call
|
|
2644
2644
|
* this before discarding those children so their shadow `<a>`/controls don't
|
|
2645
|
-
* leak
|
|
2645
|
+
* leak.
|
|
2646
|
+
*
|
|
2647
|
+
* `syncA11y` itself only creates and updates, never prunes — but it is always
|
|
2648
|
+
* followed by `enforceA11yDomOrder`, whose prune pass removes any element
|
|
2649
|
+
* whose entity is no longer reachable in the tree or no longer satisfies
|
|
2650
|
+
* {@link shouldProjectA11y}. So an entity that is `remove()`d, or whose
|
|
2651
|
+
* `interactive` flips to `false`, has its element torn down on the next synced
|
|
2652
|
+
* frame without any explicit call.
|
|
2653
|
+
*
|
|
2654
|
+
* This method is for the case that pass cannot see: a child dropped from a
|
|
2655
|
+
* component's own bookkeeping while still parented, or one discarded before
|
|
2656
|
+
* the next sync runs. Calling it is always safe and is the right habit for
|
|
2657
|
+
* pooled children.
|
|
2646
2658
|
*
|
|
2647
2659
|
* @param entity - The subtree whose shadow nodes should be removed.
|
|
2648
2660
|
*/
|
|
@@ -2931,12 +2943,34 @@ var Scene = class _Scene {
|
|
|
2931
2943
|
}
|
|
2932
2944
|
if (element.getAttribute(name) !== value) element.setAttribute(name, value);
|
|
2933
2945
|
}
|
|
2946
|
+
/**
|
|
2947
|
+
* Whether `node` should have an a11y shadow element projected for it.
|
|
2948
|
+
*
|
|
2949
|
+
* The single authority for that decision. It was previously inlined verbatim
|
|
2950
|
+
* at four call sites — `syncA11y` (create/update), `enforceA11yDomOrder`
|
|
2951
|
+
* (which ids survive pruning), `getA11yTree` (the public snapshot) and
|
|
2952
|
+
* `render` (z-index / reading-order assignment). Four copies of one predicate
|
|
2953
|
+
* is a standing correctness hazard: if any of them drifts, elements either
|
|
2954
|
+
* leak (created but never marked active, so pruned every frame and rebuilt) or
|
|
2955
|
+
* go missing from the semantic tree while still present in the DOM.
|
|
2956
|
+
*
|
|
2957
|
+
* A box is required because a zero-size element is unfocusable and
|
|
2958
|
+
* unhittable; `a11yFullViewport` is the deliberate exception, since those
|
|
2959
|
+
* nodes are boundless interaction surfaces mounted behind everything else.
|
|
2960
|
+
*
|
|
2961
|
+
* Keep this the only place the rule is written. A planned per-entity
|
|
2962
|
+
* `a11yProjection` mode ('eager' | 'onDemand' | 'never') extends exactly this
|
|
2963
|
+
* predicate, which is only tractable while it has one home.
|
|
2964
|
+
*/
|
|
2965
|
+
shouldProjectA11y(node) {
|
|
2966
|
+
return node.interactive && (node.width > 0 || node.a11yFullViewport);
|
|
2967
|
+
}
|
|
2934
2968
|
syncA11y(node) {
|
|
2935
2969
|
if (!this.a11yRoot) return;
|
|
2936
2970
|
if (node.isDOMPortal) {
|
|
2937
2971
|
return;
|
|
2938
2972
|
}
|
|
2939
|
-
if (
|
|
2973
|
+
if (this.shouldProjectA11y(node)) {
|
|
2940
2974
|
let el = this.a11yElements.get(node.id);
|
|
2941
2975
|
const attrs = node.getA11yAttributes();
|
|
2942
2976
|
const expectedTag = attrs.tag || "div";
|
|
@@ -3712,7 +3746,7 @@ var Scene = class _Scene {
|
|
|
3712
3746
|
if (node.a11yFullViewport) this.fullViewportElements.push(contentEl);
|
|
3713
3747
|
else this.normalElements.push(contentEl);
|
|
3714
3748
|
}
|
|
3715
|
-
if (
|
|
3749
|
+
if (this.shouldProjectA11y(node)) {
|
|
3716
3750
|
const el = this.a11yElements.get(node.id);
|
|
3717
3751
|
if (el) {
|
|
3718
3752
|
this.activeIds.add(node.id);
|
|
@@ -3851,7 +3885,7 @@ var Scene = class _Scene {
|
|
|
3851
3885
|
const traverse = (node, parentNode) => {
|
|
3852
3886
|
if (node.isDOMPortal) return;
|
|
3853
3887
|
let currentA11yNode = null;
|
|
3854
|
-
if (
|
|
3888
|
+
if (this.shouldProjectA11y(node)) {
|
|
3855
3889
|
const el = this.a11yElements.get(node.id);
|
|
3856
3890
|
if (el) {
|
|
3857
3891
|
const attrs = node.getA11yAttributes();
|
|
@@ -4221,7 +4255,7 @@ var Scene = class _Scene {
|
|
|
4221
4255
|
const orthogonalTolerance = Math.max(1, worldScaleX * worldScaleY) * 1e-6;
|
|
4222
4256
|
const isSimilarityTransform = Number.isFinite(worldScaleX) && Number.isFinite(worldScaleY) && Math.abs(worldScaleX - worldScaleY) <= scaleTolerance && Math.abs(a * c + b * d) <= orthogonalTolerance;
|
|
4223
4257
|
const a11yEl = isMainRenderer ? this.a11yElements.get(node.id) : void 0;
|
|
4224
|
-
const willProjectA11y = isMainRenderer &&
|
|
4258
|
+
const willProjectA11y = isMainRenderer && this.shouldProjectA11y(node);
|
|
4225
4259
|
if (a11yEl || willProjectA11y) {
|
|
4226
4260
|
const renderOrder = this.renderOrderCounter++;
|
|
4227
4261
|
if (willProjectA11y) this.a11yRenderOrders.set(node.id, renderOrder);
|
package/dist/renderer.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
var
|
|
9
|
+
var _chunkL4SWVP2Hjs = require('./chunk-L4SWVP2H.js');
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
@@ -14,4 +14,4 @@ var _chunkIYPLG4Z4js = require('./chunk-IYPLG4Z4.js');
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
exports.CanvasRenderer =
|
|
17
|
+
exports.CanvasRenderer = _chunkL4SWVP2Hjs.CanvasRenderer; exports.SVGRenderer = _chunkL4SWVP2Hjs.SVGRenderer; exports.TextRasterCache = _chunkL4SWVP2Hjs.TextRasterCache; exports.WebGPUParticleSystemManager = _chunkL4SWVP2Hjs.WebGPUParticleSystemManager; exports.createWebGLPointRenderer = _chunkL4SWVP2Hjs.createWebGLPointRenderer; exports.parseColorToRGBA = _chunkL4SWVP2Hjs.parseColorToRGBA;
|
package/dist/renderer.mjs
CHANGED
package/dist/tree/Scene.d.ts
CHANGED
|
@@ -673,7 +673,19 @@ export declare class Scene {
|
|
|
673
673
|
* without removing it from the scene graph. Components that manage dynamic
|
|
674
674
|
* interactive *child* entities (e.g. a {@link Entity}'s per-link hotspots) call
|
|
675
675
|
* this before discarding those children so their shadow `<a>`/controls don't
|
|
676
|
-
* leak
|
|
676
|
+
* leak.
|
|
677
|
+
*
|
|
678
|
+
* `syncA11y` itself only creates and updates, never prunes — but it is always
|
|
679
|
+
* followed by `enforceA11yDomOrder`, whose prune pass removes any element
|
|
680
|
+
* whose entity is no longer reachable in the tree or no longer satisfies
|
|
681
|
+
* {@link shouldProjectA11y}. So an entity that is `remove()`d, or whose
|
|
682
|
+
* `interactive` flips to `false`, has its element torn down on the next synced
|
|
683
|
+
* frame without any explicit call.
|
|
684
|
+
*
|
|
685
|
+
* This method is for the case that pass cannot see: a child dropped from a
|
|
686
|
+
* component's own bookkeeping while still parented, or one discarded before
|
|
687
|
+
* the next sync runs. Calling it is always safe and is the right habit for
|
|
688
|
+
* pooled children.
|
|
677
689
|
*
|
|
678
690
|
* @param entity - The subtree whose shadow nodes should be removed.
|
|
679
691
|
*/
|
|
@@ -756,6 +768,26 @@ export declare class Scene {
|
|
|
756
768
|
/** True when any node in the subtree has a pending animation. */
|
|
757
769
|
/** True when any node in the subtree is interactive (drives a11y sync). */
|
|
758
770
|
private syncOptionalAttribute;
|
|
771
|
+
/**
|
|
772
|
+
* Whether `node` should have an a11y shadow element projected for it.
|
|
773
|
+
*
|
|
774
|
+
* The single authority for that decision. It was previously inlined verbatim
|
|
775
|
+
* at four call sites — `syncA11y` (create/update), `enforceA11yDomOrder`
|
|
776
|
+
* (which ids survive pruning), `getA11yTree` (the public snapshot) and
|
|
777
|
+
* `render` (z-index / reading-order assignment). Four copies of one predicate
|
|
778
|
+
* is a standing correctness hazard: if any of them drifts, elements either
|
|
779
|
+
* leak (created but never marked active, so pruned every frame and rebuilt) or
|
|
780
|
+
* go missing from the semantic tree while still present in the DOM.
|
|
781
|
+
*
|
|
782
|
+
* A box is required because a zero-size element is unfocusable and
|
|
783
|
+
* unhittable; `a11yFullViewport` is the deliberate exception, since those
|
|
784
|
+
* nodes are boundless interaction surfaces mounted behind everything else.
|
|
785
|
+
*
|
|
786
|
+
* Keep this the only place the rule is written. A planned per-entity
|
|
787
|
+
* `a11yProjection` mode ('eager' | 'onDemand' | 'never') extends exactly this
|
|
788
|
+
* predicate, which is only tractable while it has one home.
|
|
789
|
+
*/
|
|
790
|
+
private shouldProjectA11y;
|
|
759
791
|
private syncA11y;
|
|
760
792
|
/**
|
|
761
793
|
* Mirror one entity's static text ({@link Entity.getContentProjection}) as a
|