@bloopjs/toodle 0.1.7 → 0.1.8
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/mod.d.ts.map +1 -1
- package/dist/mod.js +1516 -1237
- package/dist/mod.js.map +16 -14
- package/package.json +1 -1
- package/src/mod.ts +0 -2
package/dist/mod.js
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, {
|
|
5
|
+
get: all[name],
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
set: (newValue) => all[name] = () => newValue
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
|
|
1
12
|
// src/limits.ts
|
|
2
13
|
var DEFAULT_LIMITS = {
|
|
3
14
|
instanceCount: 1024 * 2,
|
|
@@ -3434,6 +3445,18 @@ var {
|
|
|
3434
3445
|
vec4: vec4n
|
|
3435
3446
|
} = wgpuMatrixAPI(ZeroArray, Array, Array, Array, Array, Array);
|
|
3436
3447
|
|
|
3448
|
+
// src/backends/mod.ts
|
|
3449
|
+
var exports_mod = {};
|
|
3450
|
+
__export(exports_mod, {
|
|
3451
|
+
isWebGPUAvailable: () => isWebGPUAvailable,
|
|
3452
|
+
isWebGL2Available: () => isWebGL2Available,
|
|
3453
|
+
detectBackend: () => detectBackend,
|
|
3454
|
+
defaultGLSLFragmentShader: () => defaultFragmentShader,
|
|
3455
|
+
WebGPUBackend: () => WebGPUBackend,
|
|
3456
|
+
WebGLBackend: () => WebGLBackend,
|
|
3457
|
+
PostProcessDefaults: () => PostProcessDefaults
|
|
3458
|
+
});
|
|
3459
|
+
|
|
3437
3460
|
// src/backends/detection.ts
|
|
3438
3461
|
async function detectBackend() {
|
|
3439
3462
|
if (typeof navigator !== "undefined" && "gpu" in navigator) {
|
|
@@ -3446,13 +3469,21 @@ async function detectBackend() {
|
|
|
3446
3469
|
}
|
|
3447
3470
|
return "webgl2";
|
|
3448
3471
|
}
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3472
|
+
function isWebGPUAvailable() {
|
|
3473
|
+
return typeof navigator !== "undefined" && "gpu" in navigator;
|
|
3474
|
+
}
|
|
3475
|
+
function isWebGL2Available() {
|
|
3476
|
+
if (typeof document === "undefined") {
|
|
3477
|
+
return false;
|
|
3478
|
+
}
|
|
3479
|
+
try {
|
|
3480
|
+
const canvas = document.createElement("canvas");
|
|
3481
|
+
const gl = canvas.getContext("webgl2");
|
|
3482
|
+
return gl !== null;
|
|
3483
|
+
} catch {
|
|
3484
|
+
return false;
|
|
3453
3485
|
}
|
|
3454
3486
|
}
|
|
3455
|
-
|
|
3456
3487
|
// src/backends/webgl2/glsl/quad.glsl.ts
|
|
3457
3488
|
var vertexShader = `#version 300 es
|
|
3458
3489
|
precision highp float;
|
|
@@ -3557,6 +3588,13 @@ void main() {
|
|
|
3557
3588
|
}
|
|
3558
3589
|
}
|
|
3559
3590
|
`;
|
|
3591
|
+
var defaultFragmentShader = fragmentShader;
|
|
3592
|
+
// src/utils/assert.ts
|
|
3593
|
+
function assert(condition, message) {
|
|
3594
|
+
if (!condition) {
|
|
3595
|
+
throw new Error(message);
|
|
3596
|
+
}
|
|
3597
|
+
}
|
|
3560
3598
|
|
|
3561
3599
|
// src/backends/webgl2/WebGLQuadShader.ts
|
|
3562
3600
|
var INSTANCE_FLOATS = 28;
|
|
@@ -3716,7 +3754,7 @@ class WebGLQuadShader {
|
|
|
3716
3754
|
}
|
|
3717
3755
|
|
|
3718
3756
|
// src/backends/webgl2/WebGLBackend.ts
|
|
3719
|
-
class
|
|
3757
|
+
class WebGLBackend {
|
|
3720
3758
|
type = "webgl2";
|
|
3721
3759
|
limits;
|
|
3722
3760
|
atlasSize;
|
|
@@ -3746,7 +3784,7 @@ class WebGLBackend2 {
|
|
|
3746
3784
|
...DEFAULT_LIMITS,
|
|
3747
3785
|
...options.limits
|
|
3748
3786
|
};
|
|
3749
|
-
const backend = new
|
|
3787
|
+
const backend = new WebGLBackend(gl, canvas, limits);
|
|
3750
3788
|
backend.createTextureAtlas("default", {
|
|
3751
3789
|
format: options.format ?? "rgba8unorm",
|
|
3752
3790
|
layers: limits.textureArrayLayers,
|
|
@@ -3835,6 +3873,58 @@ class WebGLBackend2 {
|
|
|
3835
3873
|
return this.getTextureAtlas("default")?.format ?? "rgba8unorm";
|
|
3836
3874
|
}
|
|
3837
3875
|
}
|
|
3876
|
+
// src/backends/webgpu/postprocess/mod.ts
|
|
3877
|
+
var PostProcessDefaults = {
|
|
3878
|
+
sampler(device) {
|
|
3879
|
+
return device.createSampler({
|
|
3880
|
+
label: "toodle post process sampler",
|
|
3881
|
+
magFilter: "linear",
|
|
3882
|
+
minFilter: "linear",
|
|
3883
|
+
mipmapFilter: "linear",
|
|
3884
|
+
addressModeU: "clamp-to-edge",
|
|
3885
|
+
addressModeV: "clamp-to-edge"
|
|
3886
|
+
});
|
|
3887
|
+
},
|
|
3888
|
+
vertexBufferLayout(_device) {
|
|
3889
|
+
return {
|
|
3890
|
+
arrayStride: 4 * 4,
|
|
3891
|
+
attributes: [{ shaderLocation: 0, offset: 0, format: "float32x2" }]
|
|
3892
|
+
};
|
|
3893
|
+
},
|
|
3894
|
+
vertexShader(device) {
|
|
3895
|
+
return device.createShaderModule({
|
|
3896
|
+
label: "toodle post process vertex shader",
|
|
3897
|
+
code: `
|
|
3898
|
+
struct VertexOut {
|
|
3899
|
+
@builtin(position) position: vec4<f32>,
|
|
3900
|
+
@location(0) uv: vec2<f32>,
|
|
3901
|
+
};
|
|
3902
|
+
|
|
3903
|
+
const enginePosLookup = array(vec2f(-1, 1), vec2f(-1, -1), vec2f(1, 1), vec2f(1, -1));
|
|
3904
|
+
const engineUvLookup = array(vec2f(0, 0), vec2f(0, 1), vec2f(1, 0), vec2f(1, 1));
|
|
3905
|
+
|
|
3906
|
+
@vertex
|
|
3907
|
+
fn vs_main(@builtin(vertex_index) vertexIndex: u32) -> VertexOut {
|
|
3908
|
+
var out: VertexOut;
|
|
3909
|
+
out.position = vec4(enginePosLookup[vertexIndex], 0.0, 1.0);
|
|
3910
|
+
out.uv = engineUvLookup[vertexIndex];
|
|
3911
|
+
return out;
|
|
3912
|
+
}
|
|
3913
|
+
`
|
|
3914
|
+
});
|
|
3915
|
+
},
|
|
3916
|
+
pipelineDescriptor(device) {
|
|
3917
|
+
return {
|
|
3918
|
+
label: "toodle post process pipeline descriptor",
|
|
3919
|
+
layout: "auto",
|
|
3920
|
+
primitive: { topology: "triangle-strip" },
|
|
3921
|
+
vertex: {
|
|
3922
|
+
buffers: [PostProcessDefaults.vertexBufferLayout(device)],
|
|
3923
|
+
module: PostProcessDefaults.vertexShader(device)
|
|
3924
|
+
}
|
|
3925
|
+
};
|
|
3926
|
+
}
|
|
3927
|
+
};
|
|
3838
3928
|
// node_modules/webgpu-utils/dist/1.x/webgpu-utils.module.js
|
|
3839
3929
|
var roundUpToMultipleOf = (v, multiple) => ((v + multiple - 1) / multiple | 0) * multiple;
|
|
3840
3930
|
function keysOf(obj) {
|
|
@@ -16941,7 +17031,7 @@ function convertBlendMode(mode) {
|
|
|
16941
17031
|
}
|
|
16942
17032
|
|
|
16943
17033
|
// src/backends/webgpu/WebGPUBackend.ts
|
|
16944
|
-
class
|
|
17034
|
+
class WebGPUBackend {
|
|
16945
17035
|
type = "webgpu";
|
|
16946
17036
|
limits;
|
|
16947
17037
|
atlasSize;
|
|
@@ -16986,7 +17076,7 @@ class WebGPUBackend2 {
|
|
|
16986
17076
|
...DEFAULT_LIMITS,
|
|
16987
17077
|
...options.limits
|
|
16988
17078
|
};
|
|
16989
|
-
const backend = new
|
|
17079
|
+
const backend = new WebGPUBackend(device, context, presentationFormat, limits, canvas);
|
|
16990
17080
|
backend.createTextureAtlas("default", {
|
|
16991
17081
|
format: options.format ?? "rgba8unorm",
|
|
16992
17082
|
layers: limits.textureArrayLayers,
|
|
@@ -17131,1037 +17221,755 @@ class WebGPUBackend2 {
|
|
|
17131
17221
|
return this.#renderPass;
|
|
17132
17222
|
}
|
|
17133
17223
|
}
|
|
17134
|
-
// src/
|
|
17135
|
-
|
|
17136
|
-
|
|
17137
|
-
|
|
17138
|
-
|
|
17139
|
-
|
|
17140
|
-
|
|
17141
|
-
|
|
17142
|
-
|
|
17143
|
-
|
|
17144
|
-
|
|
17145
|
-
|
|
17146
|
-
|
|
17147
|
-
|
|
17148
|
-
|
|
17149
|
-
|
|
17150
|
-
|
|
17151
|
-
}
|
|
17152
|
-
function convertScreenToWorld(screenCoordinates, camera, projectionMatrix, resolution) {
|
|
17153
|
-
const inverseViewProjectionMatrix = mat3.mul(mat3.inverse(camera.matrix), mat3.inverse(projectionMatrix));
|
|
17154
|
-
const normalizedDeviceCoordinates = {
|
|
17155
|
-
x: 2 * screenCoordinates.x / resolution.width - 1,
|
|
17156
|
-
y: 1 - 2 * screenCoordinates.y / resolution.height
|
|
17157
|
-
};
|
|
17158
|
-
return transformPoint(normalizedDeviceCoordinates, inverseViewProjectionMatrix);
|
|
17159
|
-
}
|
|
17160
|
-
function convertWorldToScreen(worldCoordinates, camera, projectionMatrix, resolution) {
|
|
17161
|
-
const viewProjectionMatrix = mat3.mul(projectionMatrix, camera.matrix);
|
|
17162
|
-
const ndcPoint = transformPoint(worldCoordinates, viewProjectionMatrix);
|
|
17163
|
-
return {
|
|
17164
|
-
x: (ndcPoint.x + 1) * resolution.width / 2,
|
|
17165
|
-
y: (1 - ndcPoint.y) * resolution.height / 2
|
|
17166
|
-
};
|
|
17167
|
-
}
|
|
17168
|
-
function transformPoint(point, matrix) {
|
|
17169
|
-
const result = vec2.transformMat3([point.x, point.y], matrix);
|
|
17170
|
-
return {
|
|
17171
|
-
x: result[0],
|
|
17172
|
-
y: result[1]
|
|
17173
|
-
};
|
|
17174
|
-
}
|
|
17175
|
-
|
|
17176
|
-
// src/scene/Batcher.ts
|
|
17177
|
-
class Batcher {
|
|
17178
|
-
nodes = [];
|
|
17179
|
-
layers = [];
|
|
17180
|
-
pipelines = [];
|
|
17181
|
-
enqueue(node) {
|
|
17182
|
-
if (node.renderComponent && node.isActive) {
|
|
17183
|
-
this.nodes.push(node);
|
|
17184
|
-
const z3 = node.layer;
|
|
17185
|
-
const layer = this.#findOrCreateLayer(z3);
|
|
17186
|
-
const pipeline = this.#findOrCreatePipeline(layer, node.renderComponent.shader);
|
|
17187
|
-
pipeline.nodes.push(node);
|
|
17188
|
-
}
|
|
17189
|
-
for (const kid of node.kids) {
|
|
17190
|
-
this.enqueue(kid);
|
|
17191
|
-
}
|
|
17192
|
-
}
|
|
17193
|
-
flush() {
|
|
17194
|
-
this.nodes = [];
|
|
17195
|
-
this.layers = [];
|
|
17196
|
-
this.pipelines = [];
|
|
17224
|
+
// src/backends/webgl2/WebGLFontPipeline.ts
|
|
17225
|
+
class WebGLFontPipeline {
|
|
17226
|
+
font;
|
|
17227
|
+
fontTexture;
|
|
17228
|
+
charDataTexture;
|
|
17229
|
+
textBufferTexture;
|
|
17230
|
+
maxCharCount;
|
|
17231
|
+
lineHeight;
|
|
17232
|
+
#gl;
|
|
17233
|
+
constructor(gl, font, fontTexture, charDataTexture, textBufferTexture, maxCharCount) {
|
|
17234
|
+
this.#gl = gl;
|
|
17235
|
+
this.font = font;
|
|
17236
|
+
this.fontTexture = fontTexture;
|
|
17237
|
+
this.charDataTexture = charDataTexture;
|
|
17238
|
+
this.textBufferTexture = textBufferTexture;
|
|
17239
|
+
this.maxCharCount = maxCharCount;
|
|
17240
|
+
this.lineHeight = font.lineHeight;
|
|
17197
17241
|
}
|
|
17198
|
-
|
|
17199
|
-
|
|
17200
|
-
|
|
17201
|
-
|
|
17202
|
-
|
|
17203
|
-
|
|
17242
|
+
static create(gl, font, maxCharCount) {
|
|
17243
|
+
const fontTexture = gl.createTexture();
|
|
17244
|
+
assert(fontTexture, "Failed to create font texture");
|
|
17245
|
+
gl.bindTexture(gl.TEXTURE_2D, fontTexture);
|
|
17246
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
17247
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
17248
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
17249
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
17250
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, font.imageBitmap);
|
|
17251
|
+
const charDataTexture = gl.createTexture();
|
|
17252
|
+
assert(charDataTexture, "Failed to create char data texture");
|
|
17253
|
+
gl.bindTexture(gl.TEXTURE_2D, charDataTexture);
|
|
17254
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
17255
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
17256
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
17257
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
17258
|
+
const charCount = font.charCount;
|
|
17259
|
+
const charTextureWidth = charCount * 2;
|
|
17260
|
+
const charTextureData = new Float32Array(charTextureWidth * 4);
|
|
17261
|
+
for (let i3 = 0;i3 < charCount; i3++) {
|
|
17262
|
+
const srcOffset = i3 * 8;
|
|
17263
|
+
const dstOffset0 = i3 * 2 * 4;
|
|
17264
|
+
const dstOffset1 = (i3 * 2 + 1) * 4;
|
|
17265
|
+
charTextureData[dstOffset0] = font.charBuffer[srcOffset];
|
|
17266
|
+
charTextureData[dstOffset0 + 1] = font.charBuffer[srcOffset + 1];
|
|
17267
|
+
charTextureData[dstOffset0 + 2] = font.charBuffer[srcOffset + 2];
|
|
17268
|
+
charTextureData[dstOffset0 + 3] = font.charBuffer[srcOffset + 3];
|
|
17269
|
+
charTextureData[dstOffset1] = font.charBuffer[srcOffset + 4];
|
|
17270
|
+
charTextureData[dstOffset1 + 1] = font.charBuffer[srcOffset + 5];
|
|
17271
|
+
charTextureData[dstOffset1 + 2] = font.charBuffer[srcOffset + 6];
|
|
17272
|
+
charTextureData[dstOffset1 + 3] = font.charBuffer[srcOffset + 7];
|
|
17204
17273
|
}
|
|
17205
|
-
|
|
17274
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA32F, charTextureWidth, 1, 0, gl.RGBA, gl.FLOAT, charTextureData);
|
|
17275
|
+
const textBufferTexture = gl.createTexture();
|
|
17276
|
+
assert(textBufferTexture, "Failed to create text buffer texture");
|
|
17277
|
+
gl.bindTexture(gl.TEXTURE_2D, textBufferTexture);
|
|
17278
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
17279
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
17280
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
17281
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
17282
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA32F, maxCharCount, 1, 0, gl.RGBA, gl.FLOAT, null);
|
|
17283
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
17284
|
+
return new WebGLFontPipeline(gl, font, fontTexture, charDataTexture, textBufferTexture, maxCharCount);
|
|
17206
17285
|
}
|
|
17207
|
-
|
|
17208
|
-
|
|
17209
|
-
|
|
17210
|
-
|
|
17211
|
-
|
|
17212
|
-
|
|
17213
|
-
|
|
17214
|
-
|
|
17286
|
+
updateTextBuffer(data, glyphCount) {
|
|
17287
|
+
const gl = this.#gl;
|
|
17288
|
+
gl.bindTexture(gl.TEXTURE_2D, this.textBufferTexture);
|
|
17289
|
+
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, glyphCount, 1, gl.RGBA, gl.FLOAT, data);
|
|
17290
|
+
}
|
|
17291
|
+
destroy() {
|
|
17292
|
+
const gl = this.#gl;
|
|
17293
|
+
gl.deleteTexture(this.fontTexture);
|
|
17294
|
+
gl.deleteTexture(this.charDataTexture);
|
|
17295
|
+
gl.deleteTexture(this.textBufferTexture);
|
|
17215
17296
|
}
|
|
17216
17297
|
}
|
|
17217
17298
|
|
|
17218
|
-
// src/
|
|
17219
|
-
|
|
17220
|
-
|
|
17221
|
-
|
|
17222
|
-
|
|
17223
|
-
return radians * (180 / Math.PI);
|
|
17224
|
-
}
|
|
17225
|
-
|
|
17226
|
-
// src/scene/Camera.ts
|
|
17227
|
-
class Camera {
|
|
17228
|
-
#position = { x: 0, y: 0 };
|
|
17229
|
-
#zoom = 1;
|
|
17230
|
-
#rotation = 0;
|
|
17231
|
-
#isDirty = true;
|
|
17232
|
-
#matrix = mat3.create();
|
|
17233
|
-
get zoom() {
|
|
17234
|
-
return this.#zoom;
|
|
17235
|
-
}
|
|
17236
|
-
set zoom(value) {
|
|
17237
|
-
this.#zoom = value;
|
|
17238
|
-
this.setDirty();
|
|
17239
|
-
}
|
|
17240
|
-
get rotation() {
|
|
17241
|
-
return rad2deg(this.#rotation);
|
|
17242
|
-
}
|
|
17243
|
-
set rotation(value) {
|
|
17244
|
-
this.#rotation = deg2rad(value);
|
|
17245
|
-
this.setDirty();
|
|
17246
|
-
}
|
|
17247
|
-
get rotationRadians() {
|
|
17248
|
-
return this.#rotation;
|
|
17249
|
-
}
|
|
17250
|
-
set rotationRadians(value) {
|
|
17251
|
-
this.#rotation = value;
|
|
17252
|
-
this.setDirty();
|
|
17253
|
-
}
|
|
17254
|
-
get x() {
|
|
17255
|
-
return this.#position.x;
|
|
17256
|
-
}
|
|
17257
|
-
get y() {
|
|
17258
|
-
return this.#position.y;
|
|
17259
|
-
}
|
|
17260
|
-
set x(value) {
|
|
17261
|
-
this.#position.x = value;
|
|
17262
|
-
this.setDirty();
|
|
17263
|
-
}
|
|
17264
|
-
set y(value) {
|
|
17265
|
-
this.#position.y = value;
|
|
17266
|
-
this.setDirty();
|
|
17267
|
-
}
|
|
17268
|
-
get matrix() {
|
|
17269
|
-
if (this.#isDirty) {
|
|
17270
|
-
this.#isDirty = false;
|
|
17271
|
-
this.#matrix = createViewMatrix(this, this.#matrix);
|
|
17272
|
-
}
|
|
17273
|
-
return this.#matrix;
|
|
17274
|
-
}
|
|
17275
|
-
setDirty() {
|
|
17276
|
-
this.#isDirty = true;
|
|
17299
|
+
// src/utils/error.ts
|
|
17300
|
+
var warnings = new Map;
|
|
17301
|
+
function warnOnce(key, msg) {
|
|
17302
|
+
if (warnings.has(key)) {
|
|
17303
|
+
return;
|
|
17277
17304
|
}
|
|
17305
|
+
warnings.set(key, true);
|
|
17306
|
+
console.warn(msg ?? key);
|
|
17278
17307
|
}
|
|
17279
17308
|
|
|
17280
|
-
// src/
|
|
17281
|
-
class
|
|
17282
|
-
static nextId = 1;
|
|
17309
|
+
// src/text/MsdfFont.ts
|
|
17310
|
+
class MsdfFont {
|
|
17283
17311
|
id;
|
|
17284
|
-
|
|
17285
|
-
|
|
17286
|
-
|
|
17287
|
-
|
|
17288
|
-
|
|
17289
|
-
|
|
17290
|
-
|
|
17291
|
-
#
|
|
17292
|
-
#
|
|
17293
|
-
#
|
|
17294
|
-
|
|
17295
|
-
|
|
17296
|
-
|
|
17297
|
-
|
|
17298
|
-
|
|
17299
|
-
|
|
17300
|
-
|
|
17301
|
-
|
|
17302
|
-
this
|
|
17303
|
-
|
|
17304
|
-
|
|
17305
|
-
|
|
17306
|
-
|
|
17307
|
-
|
|
17308
|
-
|
|
17309
|
-
|
|
17310
|
-
|
|
17311
|
-
|
|
17312
|
-
this.#matrix = mat3.identity();
|
|
17313
|
-
this.#renderComponent = opts?.render ?? null;
|
|
17314
|
-
this.#layer = opts?.layer ?? null;
|
|
17315
|
-
this.#isActive = opts?.isActive ?? true;
|
|
17316
|
-
this.label = opts?.label ?? undefined;
|
|
17317
|
-
this.#size = opts?.size ?? null;
|
|
17318
|
-
this.#key = opts?.key ?? null;
|
|
17319
|
-
for (const kid of opts?.kids ?? []) {
|
|
17320
|
-
this.add(kid);
|
|
17321
|
-
}
|
|
17322
|
-
const self = this;
|
|
17323
|
-
this.#positionProxy = {
|
|
17324
|
-
get x() {
|
|
17325
|
-
return self.#transform.position.x;
|
|
17326
|
-
},
|
|
17327
|
-
set x(value) {
|
|
17328
|
-
self.#transform.position.x = value;
|
|
17329
|
-
self.setDirty();
|
|
17330
|
-
},
|
|
17331
|
-
get y() {
|
|
17332
|
-
return self.#transform.position.y;
|
|
17333
|
-
},
|
|
17334
|
-
set y(value) {
|
|
17335
|
-
self.#transform.position.y = value;
|
|
17336
|
-
self.setDirty();
|
|
17337
|
-
}
|
|
17338
|
-
};
|
|
17339
|
-
this.#scaleProxy = {
|
|
17340
|
-
get x() {
|
|
17341
|
-
return self.#transform.scale.x;
|
|
17342
|
-
},
|
|
17343
|
-
set x(value) {
|
|
17344
|
-
self.#transform.scale.x = value;
|
|
17345
|
-
self.setDirty();
|
|
17346
|
-
},
|
|
17347
|
-
get y() {
|
|
17348
|
-
return self.#transform.scale.y;
|
|
17349
|
-
},
|
|
17350
|
-
set y(value) {
|
|
17351
|
-
self.#transform.scale.y = value;
|
|
17352
|
-
self.setDirty();
|
|
17312
|
+
json;
|
|
17313
|
+
imageBitmap;
|
|
17314
|
+
name;
|
|
17315
|
+
charset;
|
|
17316
|
+
charCount;
|
|
17317
|
+
lineHeight;
|
|
17318
|
+
charBuffer;
|
|
17319
|
+
#kernings;
|
|
17320
|
+
#chars;
|
|
17321
|
+
#fallbackCharCode;
|
|
17322
|
+
constructor(id, json, imageBitmap) {
|
|
17323
|
+
this.id = id;
|
|
17324
|
+
this.json = json;
|
|
17325
|
+
this.imageBitmap = imageBitmap;
|
|
17326
|
+
const charArray = Object.values(json.chars);
|
|
17327
|
+
this.charCount = charArray.length;
|
|
17328
|
+
this.lineHeight = json.common.lineHeight;
|
|
17329
|
+
this.charset = json.info.charset;
|
|
17330
|
+
this.name = json.info.face;
|
|
17331
|
+
this.#kernings = new Map;
|
|
17332
|
+
if (json.kernings) {
|
|
17333
|
+
for (const kearning of json.kernings) {
|
|
17334
|
+
let charKerning = this.#kernings.get(kearning.first);
|
|
17335
|
+
if (!charKerning) {
|
|
17336
|
+
charKerning = new Map;
|
|
17337
|
+
this.#kernings.set(kearning.first, charKerning);
|
|
17338
|
+
}
|
|
17339
|
+
charKerning.set(kearning.second, kearning.amount);
|
|
17353
17340
|
}
|
|
17354
|
-
};
|
|
17355
|
-
}
|
|
17356
|
-
add(kid, index) {
|
|
17357
|
-
kid.#parent = this;
|
|
17358
|
-
if (index === undefined) {
|
|
17359
|
-
this.#kids.push(kid);
|
|
17360
|
-
} else {
|
|
17361
|
-
this.#kids.splice(index, 0, kid);
|
|
17362
17341
|
}
|
|
17363
|
-
|
|
17364
|
-
|
|
17365
|
-
|
|
17366
|
-
|
|
17367
|
-
|
|
17368
|
-
|
|
17369
|
-
|
|
17370
|
-
|
|
17371
|
-
|
|
17372
|
-
|
|
17373
|
-
|
|
17374
|
-
|
|
17375
|
-
|
|
17376
|
-
|
|
17377
|
-
|
|
17378
|
-
|
|
17379
|
-
|
|
17380
|
-
|
|
17381
|
-
set position(value) {
|
|
17382
|
-
this.#transform.position = value;
|
|
17383
|
-
this.setDirty();
|
|
17384
|
-
}
|
|
17385
|
-
get position() {
|
|
17386
|
-
return this.#positionProxy;
|
|
17387
|
-
}
|
|
17388
|
-
set x(value) {
|
|
17389
|
-
this.#transform.position.x = value;
|
|
17390
|
-
this.setDirty();
|
|
17391
|
-
}
|
|
17392
|
-
get x() {
|
|
17393
|
-
return this.#transform.position.x;
|
|
17394
|
-
}
|
|
17395
|
-
set y(value) {
|
|
17396
|
-
this.#transform.position.y = value;
|
|
17397
|
-
this.setDirty();
|
|
17398
|
-
}
|
|
17399
|
-
get y() {
|
|
17400
|
-
return this.#transform.position.y;
|
|
17401
|
-
}
|
|
17402
|
-
set rotation(value) {
|
|
17403
|
-
this.#transform.rotation = deg2rad(value);
|
|
17404
|
-
this.setDirty();
|
|
17405
|
-
}
|
|
17406
|
-
get rotation() {
|
|
17407
|
-
return rad2deg(this.#transform.rotation);
|
|
17408
|
-
}
|
|
17409
|
-
get rotationRadians() {
|
|
17410
|
-
return this.#transform.rotation;
|
|
17411
|
-
}
|
|
17412
|
-
set rotationRadians(value) {
|
|
17413
|
-
this.#transform.rotation = value;
|
|
17414
|
-
this.setDirty();
|
|
17415
|
-
}
|
|
17416
|
-
get scale() {
|
|
17417
|
-
return this.#scaleProxy;
|
|
17418
|
-
}
|
|
17419
|
-
set scale(value) {
|
|
17420
|
-
if (typeof value === "number") {
|
|
17421
|
-
this.#transform.scale = { x: value, y: value };
|
|
17422
|
-
} else {
|
|
17423
|
-
this.#transform.scale = value;
|
|
17342
|
+
this.#chars = new Map;
|
|
17343
|
+
const charCount = Object.values(json.chars).length;
|
|
17344
|
+
this.charBuffer = new Float32Array(charCount * 8);
|
|
17345
|
+
let offset = 0;
|
|
17346
|
+
const u3 = 1 / json.common.scaleW;
|
|
17347
|
+
const v3 = 1 / json.common.scaleH;
|
|
17348
|
+
for (const [i3, char] of json.chars.entries()) {
|
|
17349
|
+
this.#chars.set(char.id, char);
|
|
17350
|
+
this.#chars.get(char.id).charIndex = i3;
|
|
17351
|
+
this.charBuffer[offset] = char.x * u3;
|
|
17352
|
+
this.charBuffer[offset + 1] = char.y * v3;
|
|
17353
|
+
this.charBuffer[offset + 2] = char.width * u3;
|
|
17354
|
+
this.charBuffer[offset + 3] = char.height * v3;
|
|
17355
|
+
this.charBuffer[offset + 4] = char.width;
|
|
17356
|
+
this.charBuffer[offset + 5] = char.height;
|
|
17357
|
+
this.charBuffer[offset + 6] = char.xoffset;
|
|
17358
|
+
this.charBuffer[offset + 7] = -char.yoffset;
|
|
17359
|
+
offset += 8;
|
|
17424
17360
|
}
|
|
17425
|
-
this.setDirty();
|
|
17426
|
-
}
|
|
17427
|
-
set size(value) {
|
|
17428
|
-
this.#size = value;
|
|
17429
|
-
this.setDirty();
|
|
17430
17361
|
}
|
|
17431
|
-
|
|
17432
|
-
|
|
17433
|
-
|
|
17434
|
-
|
|
17435
|
-
|
|
17436
|
-
|
|
17437
|
-
return 1;
|
|
17362
|
+
getChar(charCode) {
|
|
17363
|
+
const char = this.#chars.get(charCode);
|
|
17364
|
+
if (!char) {
|
|
17365
|
+
const fallbackCharacter = this.#chars.get(this.#fallbackCharCode ?? this.#chars.keys().toArray()[0]);
|
|
17366
|
+
warnOnce(`unknown_char_${this.name}`, `Couldn't find character ${charCode} in characters for font ${this.name} -- defaulting to first available character "${fallbackCharacter.char}"`);
|
|
17367
|
+
return fallbackCharacter;
|
|
17438
17368
|
}
|
|
17439
|
-
return
|
|
17369
|
+
return char;
|
|
17440
17370
|
}
|
|
17441
|
-
|
|
17442
|
-
|
|
17443
|
-
|
|
17444
|
-
|
|
17445
|
-
|
|
17446
|
-
|
|
17447
|
-
parent = parent.#parent;
|
|
17448
|
-
isActive = isActive && parent.#isActive;
|
|
17371
|
+
getXAdvance(charCode, nextCharCode = -1) {
|
|
17372
|
+
const char = this.getChar(charCode);
|
|
17373
|
+
if (nextCharCode >= 0) {
|
|
17374
|
+
const kerning = this.#kernings.get(charCode);
|
|
17375
|
+
if (kerning) {
|
|
17376
|
+
return char.xadvance + (kerning.get(nextCharCode) ?? 0);
|
|
17449
17377
|
}
|
|
17450
|
-
this.#cache.isActive = isActive;
|
|
17451
17378
|
}
|
|
17452
|
-
return
|
|
17453
|
-
}
|
|
17454
|
-
set isActive(value) {
|
|
17455
|
-
this.#isActive = value;
|
|
17456
|
-
this.setDirty();
|
|
17379
|
+
return char.xadvance;
|
|
17457
17380
|
}
|
|
17458
|
-
|
|
17459
|
-
|
|
17460
|
-
|
|
17381
|
+
static async create(id, fontJsonUrl) {
|
|
17382
|
+
const response = await fetch(fontJsonUrl);
|
|
17383
|
+
const json = await response.json();
|
|
17384
|
+
const i3 = fontJsonUrl.href.lastIndexOf("/");
|
|
17385
|
+
const baseUrl = i3 !== -1 ? fontJsonUrl.href.substring(0, i3 + 1) : undefined;
|
|
17386
|
+
if (json.pages.length < 1) {
|
|
17387
|
+
throw new Error(`Can't create an msdf font without a reference to the page url in the json`);
|
|
17461
17388
|
}
|
|
17462
|
-
if (
|
|
17463
|
-
|
|
17464
|
-
let parent = this;
|
|
17465
|
-
while (parent.#parent) {
|
|
17466
|
-
parent = parent.#parent;
|
|
17467
|
-
if (parent.hasExplicitLayer) {
|
|
17468
|
-
this.#cache.layer = parent.#layer;
|
|
17469
|
-
return this.#cache.layer;
|
|
17470
|
-
}
|
|
17471
|
-
}
|
|
17472
|
-
this.#cache.layer = 0;
|
|
17389
|
+
if (json.pages.length > 1) {
|
|
17390
|
+
throw new Error(`Can't create an msdf font with more than one page`);
|
|
17473
17391
|
}
|
|
17474
|
-
|
|
17475
|
-
|
|
17476
|
-
|
|
17477
|
-
return
|
|
17478
|
-
}
|
|
17479
|
-
set layer(value) {
|
|
17480
|
-
this.#layer = value;
|
|
17481
|
-
this.setDirty();
|
|
17392
|
+
const textureUrl = baseUrl + json.pages[0];
|
|
17393
|
+
const textureResponse = await fetch(textureUrl);
|
|
17394
|
+
const bitmap = await createImageBitmap(await textureResponse.blob());
|
|
17395
|
+
return new MsdfFont(id, json, bitmap);
|
|
17482
17396
|
}
|
|
17483
|
-
|
|
17484
|
-
|
|
17485
|
-
|
|
17486
|
-
|
|
17487
|
-
|
|
17488
|
-
this.#
|
|
17489
|
-
|
|
17490
|
-
|
|
17491
|
-
} else {
|
|
17492
|
-
mat3.identity(this.#matrix);
|
|
17493
|
-
}
|
|
17494
|
-
this.#cache.matrix = createModelMatrix(this.transform, this.#matrix);
|
|
17397
|
+
set fallbackCharacter(character) {
|
|
17398
|
+
const charCode = character.charCodeAt(0);
|
|
17399
|
+
if (this.#chars.has(charCode)) {
|
|
17400
|
+
this.#fallbackCharCode = charCode;
|
|
17401
|
+
} else {
|
|
17402
|
+
const fallbackCode = this.#chars.keys().toArray()[0];
|
|
17403
|
+
console.warn(`${character} character does not exist in font ${this.name} defaulting to "${this.#chars.get(fallbackCode)?.char}".`);
|
|
17404
|
+
this.#fallbackCharCode = fallbackCode;
|
|
17495
17405
|
}
|
|
17496
|
-
return this.#cache.matrix;
|
|
17497
17406
|
}
|
|
17498
|
-
|
|
17499
|
-
|
|
17500
|
-
|
|
17501
|
-
|
|
17502
|
-
|
|
17503
|
-
|
|
17504
|
-
|
|
17505
|
-
|
|
17506
|
-
|
|
17507
|
-
|
|
17508
|
-
|
|
17509
|
-
|
|
17510
|
-
|
|
17511
|
-
const yValues = corners.map((c3) => c3[1]);
|
|
17512
|
-
this.#cache.bounds = {
|
|
17513
|
-
x: center[0],
|
|
17514
|
-
y: center[1],
|
|
17515
|
-
left: Math.min(xValues[0], xValues[1], xValues[2], xValues[3]),
|
|
17516
|
-
right: Math.max(xValues[0], xValues[1], xValues[2], xValues[3]),
|
|
17517
|
-
top: Math.max(yValues[0], yValues[1], yValues[2], yValues[3]),
|
|
17518
|
-
bottom: Math.min(yValues[0], yValues[1], yValues[2], yValues[3])
|
|
17519
|
-
};
|
|
17520
|
-
}
|
|
17521
|
-
return this.#cache.bounds;
|
|
17407
|
+
}
|
|
17408
|
+
|
|
17409
|
+
// src/text/shaping.ts
|
|
17410
|
+
var TAB_SPACES = 4;
|
|
17411
|
+
function shapeText(font, text, blockSize, fontSize, formatting, textArray, initialFloatOffset = 0, debug = false) {
|
|
17412
|
+
let offset = initialFloatOffset;
|
|
17413
|
+
const measurements = measureText(font, text, formatting.wordWrap);
|
|
17414
|
+
const alignment = formatting.align || "left";
|
|
17415
|
+
const em2px = fontSize / font.lineHeight;
|
|
17416
|
+
const hackHasExplicitBlock = blockSize.width !== measurements.width;
|
|
17417
|
+
let debugData = null;
|
|
17418
|
+
if (debug) {
|
|
17419
|
+
debugData = [];
|
|
17522
17420
|
}
|
|
17523
|
-
|
|
17524
|
-
|
|
17525
|
-
|
|
17526
|
-
|
|
17527
|
-
|
|
17528
|
-
|
|
17529
|
-
|
|
17530
|
-
|
|
17531
|
-
|
|
17532
|
-
|
|
17533
|
-
|
|
17534
|
-
|
|
17535
|
-
|
|
17536
|
-
|
|
17421
|
+
for (const word of measurements.words) {
|
|
17422
|
+
for (const glyph of word.glyphs) {
|
|
17423
|
+
let lineOffset = 0;
|
|
17424
|
+
if (alignment === "center") {
|
|
17425
|
+
lineOffset = measurements.width * -0.5 - (measurements.width - measurements.lineWidths[glyph.line]) * -0.5;
|
|
17426
|
+
} else if (alignment === "right") {
|
|
17427
|
+
const blockSizeEm = blockSize.width / em2px;
|
|
17428
|
+
const delta = measurements.width - measurements.lineWidths[glyph.line];
|
|
17429
|
+
lineOffset = (hackHasExplicitBlock ? blockSizeEm / 2 : measurements.width / 2) - measurements.width + delta;
|
|
17430
|
+
} else if (alignment === "left") {
|
|
17431
|
+
const blockSizeEm = blockSize.width / em2px;
|
|
17432
|
+
lineOffset = hackHasExplicitBlock ? -blockSizeEm / 2 : -measurements.width / 2;
|
|
17433
|
+
}
|
|
17434
|
+
if (debug && debugData) {
|
|
17435
|
+
debugData.push({
|
|
17436
|
+
line: glyph.line,
|
|
17437
|
+
word: word.glyphs.map((g3) => g3.char.char).join(""),
|
|
17438
|
+
glyph: glyph.char.char,
|
|
17439
|
+
startX: word.startX,
|
|
17440
|
+
glyphX: glyph.offset[0],
|
|
17441
|
+
advance: glyph.char.xadvance,
|
|
17442
|
+
lineOffset,
|
|
17443
|
+
startY: word.startY,
|
|
17444
|
+
glyphY: glyph.offset[1]
|
|
17445
|
+
});
|
|
17446
|
+
}
|
|
17447
|
+
textArray[offset] = word.startX + glyph.offset[0] + lineOffset;
|
|
17448
|
+
textArray[offset + 1] = word.startY + glyph.offset[1];
|
|
17449
|
+
textArray[offset + 2] = glyph.char.charIndex;
|
|
17450
|
+
offset += 4;
|
|
17451
|
+
}
|
|
17537
17452
|
}
|
|
17538
|
-
|
|
17539
|
-
|
|
17453
|
+
if (debug && debugData) {
|
|
17454
|
+
console.table(debugData);
|
|
17540
17455
|
}
|
|
17541
|
-
|
|
17542
|
-
|
|
17456
|
+
}
|
|
17457
|
+
function measureText(font, text, wordWrap) {
|
|
17458
|
+
let maxWidth = 0;
|
|
17459
|
+
const lineWidths = [];
|
|
17460
|
+
let textOffsetX = 0;
|
|
17461
|
+
let textOffsetY = 0;
|
|
17462
|
+
let line = 0;
|
|
17463
|
+
let printedCharCount = 0;
|
|
17464
|
+
let nextCharCode = text.charCodeAt(0);
|
|
17465
|
+
let word = { glyphs: [], width: 0, startX: 0, startY: 0 };
|
|
17466
|
+
const words = [];
|
|
17467
|
+
for (let i3 = 0;i3 < text.length; i3++) {
|
|
17468
|
+
const isLastLetter = i3 === text.length - 1;
|
|
17469
|
+
const charCode = nextCharCode;
|
|
17470
|
+
nextCharCode = i3 < text.length - 1 ? text.charCodeAt(i3 + 1) : -1;
|
|
17471
|
+
switch (charCode) {
|
|
17472
|
+
case 9 /* HorizontalTab */:
|
|
17473
|
+
insertSpaces(TAB_SPACES);
|
|
17474
|
+
break;
|
|
17475
|
+
case 10 /* Newline */:
|
|
17476
|
+
flushLine();
|
|
17477
|
+
flushWord();
|
|
17478
|
+
break;
|
|
17479
|
+
case 13 /* CarriageReturn */:
|
|
17480
|
+
break;
|
|
17481
|
+
case 32 /* Space */:
|
|
17482
|
+
insertSpaces(1);
|
|
17483
|
+
break;
|
|
17484
|
+
default: {
|
|
17485
|
+
const advance = font.getXAdvance(charCode, nextCharCode);
|
|
17486
|
+
if (wordWrap && wordWrap.breakOn === "character" && textOffsetX + advance > wordWrap.emWidth) {
|
|
17487
|
+
if (word.startX === 0) {
|
|
17488
|
+
flushWord();
|
|
17489
|
+
} else {
|
|
17490
|
+
lineWidths.push(textOffsetX - word.width);
|
|
17491
|
+
line++;
|
|
17492
|
+
maxWidth = Math.max(maxWidth, textOffsetX);
|
|
17493
|
+
textOffsetX = word.width;
|
|
17494
|
+
textOffsetY -= font.lineHeight;
|
|
17495
|
+
word.startX = 0;
|
|
17496
|
+
word.startY = textOffsetY;
|
|
17497
|
+
word.glyphs.forEach((g3) => {
|
|
17498
|
+
g3.line = line;
|
|
17499
|
+
});
|
|
17500
|
+
}
|
|
17501
|
+
}
|
|
17502
|
+
word.glyphs.push({
|
|
17503
|
+
char: font.getChar(charCode),
|
|
17504
|
+
offset: [word.width, 0],
|
|
17505
|
+
line
|
|
17506
|
+
});
|
|
17507
|
+
if (isLastLetter) {
|
|
17508
|
+
flushWord();
|
|
17509
|
+
}
|
|
17510
|
+
word.width += advance;
|
|
17511
|
+
textOffsetX += advance;
|
|
17512
|
+
}
|
|
17513
|
+
}
|
|
17543
17514
|
}
|
|
17544
|
-
|
|
17545
|
-
|
|
17515
|
+
lineWidths.push(textOffsetX);
|
|
17516
|
+
maxWidth = Math.max(maxWidth, textOffsetX);
|
|
17517
|
+
const lineCount = lineWidths.length;
|
|
17518
|
+
return {
|
|
17519
|
+
width: maxWidth,
|
|
17520
|
+
height: lineCount * font.lineHeight,
|
|
17521
|
+
lineWidths,
|
|
17522
|
+
lineCount,
|
|
17523
|
+
printedCharCount,
|
|
17524
|
+
words
|
|
17525
|
+
};
|
|
17526
|
+
function flushWord() {
|
|
17527
|
+
printedCharCount += word.glyphs.length;
|
|
17528
|
+
words.push(word);
|
|
17529
|
+
word = {
|
|
17530
|
+
glyphs: [],
|
|
17531
|
+
width: 0,
|
|
17532
|
+
startX: textOffsetX,
|
|
17533
|
+
startY: textOffsetY
|
|
17534
|
+
};
|
|
17546
17535
|
}
|
|
17547
|
-
|
|
17548
|
-
|
|
17536
|
+
function flushLine() {
|
|
17537
|
+
lineWidths.push(textOffsetX);
|
|
17538
|
+
line++;
|
|
17539
|
+
maxWidth = Math.max(maxWidth, textOffsetX);
|
|
17540
|
+
textOffsetX = 0;
|
|
17541
|
+
textOffsetY -= font.lineHeight;
|
|
17549
17542
|
}
|
|
17550
|
-
|
|
17551
|
-
|
|
17543
|
+
function insertSpaces(spaces) {
|
|
17544
|
+
if (spaces < 1)
|
|
17545
|
+
spaces = 1;
|
|
17546
|
+
textOffsetX += font.getXAdvance(32 /* Space */) * spaces;
|
|
17547
|
+
if (wordWrap?.breakOn === "word" && textOffsetX >= wordWrap.emWidth) {
|
|
17548
|
+
flushLine();
|
|
17549
|
+
}
|
|
17550
|
+
flushWord();
|
|
17552
17551
|
}
|
|
17553
|
-
|
|
17554
|
-
|
|
17552
|
+
}
|
|
17553
|
+
function findLargestFontSize(font, text, size, formatting) {
|
|
17554
|
+
if (!formatting.fontSize) {
|
|
17555
|
+
throw new Error("fontSize is required for shrinkToFit");
|
|
17555
17556
|
}
|
|
17556
|
-
|
|
17557
|
-
|
|
17558
|
-
for (const child of this.#kids) {
|
|
17559
|
-
child.delete();
|
|
17560
|
-
}
|
|
17561
|
-
this.#kids = [];
|
|
17562
|
-
this.#isActive = false;
|
|
17563
|
-
this.#layer = null;
|
|
17564
|
-
this.#renderComponent = null;
|
|
17557
|
+
if (!formatting.shrinkToFit) {
|
|
17558
|
+
throw new Error("shrinkToFit is required for findLargestFontSize");
|
|
17565
17559
|
}
|
|
17566
|
-
|
|
17567
|
-
|
|
17568
|
-
|
|
17569
|
-
|
|
17560
|
+
const minSize = formatting.shrinkToFit.minFontSize;
|
|
17561
|
+
const maxSize = formatting.shrinkToFit.maxFontSize ?? formatting.fontSize;
|
|
17562
|
+
const maxLines = formatting.shrinkToFit.maxLines ?? Number.POSITIVE_INFINITY;
|
|
17563
|
+
const threshold = 0.5;
|
|
17564
|
+
let low = minSize;
|
|
17565
|
+
let high = maxSize;
|
|
17566
|
+
while (high - low > threshold) {
|
|
17567
|
+
const testSize = (low + high) / 2;
|
|
17568
|
+
const testMeasure = measureText(font, text, formatting.wordWrap);
|
|
17569
|
+
const padding = formatting.shrinkToFit.padding ?? 0;
|
|
17570
|
+
const scaledWidth = testMeasure.width * (testSize / font.lineHeight);
|
|
17571
|
+
const scaledHeight = testMeasure.height * (testSize / font.lineHeight);
|
|
17572
|
+
const fitsWidth = scaledWidth <= size.width - size.width * padding;
|
|
17573
|
+
const fitsHeight = scaledHeight <= size.height - size.height * padding;
|
|
17574
|
+
const fitsLines = testMeasure.lineCount <= maxLines;
|
|
17575
|
+
if (fitsWidth && fitsHeight && fitsLines) {
|
|
17576
|
+
low = testSize;
|
|
17577
|
+
} else {
|
|
17578
|
+
high = testSize;
|
|
17570
17579
|
}
|
|
17571
|
-
this.#kids.splice(childIndex, 1);
|
|
17572
|
-
kid.#parent = null;
|
|
17573
|
-
kid.setDirty();
|
|
17574
|
-
}
|
|
17575
|
-
#adjustWorldPosition(delta) {
|
|
17576
|
-
const inverseMatrix = mat3.inverse(this.#parent?.matrix ?? mat3.identity());
|
|
17577
|
-
inverseMatrix[8] = inverseMatrix[9] = 0;
|
|
17578
|
-
const localDelta = vec2.transformMat3(delta, inverseMatrix);
|
|
17579
|
-
this.#transform.position.x += localDelta[0];
|
|
17580
|
-
this.#transform.position.y += localDelta[1];
|
|
17581
|
-
this.setDirty();
|
|
17582
|
-
}
|
|
17583
|
-
setDirty() {
|
|
17584
|
-
this.#cache = null;
|
|
17585
|
-
this.#kids.forEach((kid) => kid.setDirty());
|
|
17586
|
-
}
|
|
17587
|
-
static parse(json) {
|
|
17588
|
-
const obj = JSON.parse(json, reviver);
|
|
17589
|
-
return new SceneNode(obj);
|
|
17590
|
-
}
|
|
17591
|
-
toJSON() {
|
|
17592
|
-
return {
|
|
17593
|
-
id: this.id,
|
|
17594
|
-
label: this.label,
|
|
17595
|
-
transform: this.#transform,
|
|
17596
|
-
layer: this.#layer,
|
|
17597
|
-
isActive: this.#isActive,
|
|
17598
|
-
kids: this.#kids,
|
|
17599
|
-
render: this.#renderComponent
|
|
17600
|
-
};
|
|
17601
17580
|
}
|
|
17581
|
+
return low;
|
|
17602
17582
|
}
|
|
17603
|
-
|
|
17604
|
-
|
|
17605
|
-
|
|
17606
|
-
|
|
17607
|
-
|
|
17608
|
-
|
|
17609
|
-
|
|
17610
|
-
}
|
|
17611
|
-
if (value.length === 3) {
|
|
17612
|
-
return value;
|
|
17613
|
-
}
|
|
17614
|
-
if (value.length === 4) {
|
|
17615
|
-
return value;
|
|
17616
|
-
}
|
|
17617
|
-
}
|
|
17618
|
-
return value;
|
|
17583
|
+
|
|
17584
|
+
// src/math/angle.ts
|
|
17585
|
+
function deg2rad(degrees) {
|
|
17586
|
+
return degrees * (Math.PI / 180);
|
|
17587
|
+
}
|
|
17588
|
+
function rad2deg(radians) {
|
|
17589
|
+
return radians * (180 / Math.PI);
|
|
17619
17590
|
}
|
|
17620
17591
|
|
|
17621
|
-
// src/
|
|
17622
|
-
|
|
17623
|
-
|
|
17624
|
-
|
|
17625
|
-
|
|
17626
|
-
|
|
17627
|
-
|
|
17628
|
-
|
|
17629
|
-
|
|
17630
|
-
|
|
17592
|
+
// src/math/matrix.ts
|
|
17593
|
+
function createProjectionMatrix(resolution, dst) {
|
|
17594
|
+
const { width, height } = resolution;
|
|
17595
|
+
return mat3.scaling([2 / width, 2 / height], dst);
|
|
17596
|
+
}
|
|
17597
|
+
function createViewMatrix(camera, target) {
|
|
17598
|
+
const matrix = mat3.identity(target);
|
|
17599
|
+
mat3.scale(matrix, [camera.zoom, camera.zoom], matrix);
|
|
17600
|
+
mat3.rotate(matrix, camera.rotationRadians, matrix);
|
|
17601
|
+
mat3.translate(matrix, [-camera.x, -camera.y], matrix);
|
|
17602
|
+
return matrix;
|
|
17603
|
+
}
|
|
17604
|
+
function createModelMatrix(transform, base) {
|
|
17605
|
+
mat3.translate(base, [transform.position.x, transform.position.y], base);
|
|
17606
|
+
mat3.rotate(base, transform.rotation, base);
|
|
17607
|
+
mat3.scale(base, [transform.scale.x, transform.scale.y], base);
|
|
17608
|
+
return base;
|
|
17609
|
+
}
|
|
17610
|
+
function convertScreenToWorld(screenCoordinates, camera, projectionMatrix, resolution) {
|
|
17611
|
+
const inverseViewProjectionMatrix = mat3.mul(mat3.inverse(camera.matrix), mat3.inverse(projectionMatrix));
|
|
17612
|
+
const normalizedDeviceCoordinates = {
|
|
17613
|
+
x: 2 * screenCoordinates.x / resolution.width - 1,
|
|
17614
|
+
y: 1 - 2 * screenCoordinates.y / resolution.height
|
|
17615
|
+
};
|
|
17616
|
+
return transformPoint(normalizedDeviceCoordinates, inverseViewProjectionMatrix);
|
|
17617
|
+
}
|
|
17618
|
+
function convertWorldToScreen(worldCoordinates, camera, projectionMatrix, resolution) {
|
|
17619
|
+
const viewProjectionMatrix = mat3.mul(projectionMatrix, camera.matrix);
|
|
17620
|
+
const ndcPoint = transformPoint(worldCoordinates, viewProjectionMatrix);
|
|
17621
|
+
return {
|
|
17622
|
+
x: (ndcPoint.x + 1) * resolution.width / 2,
|
|
17623
|
+
y: (1 - ndcPoint.y) * resolution.height / 2
|
|
17624
|
+
};
|
|
17625
|
+
}
|
|
17626
|
+
function transformPoint(point, matrix) {
|
|
17627
|
+
const result = vec2.transformMat3([point.x, point.y], matrix);
|
|
17628
|
+
return {
|
|
17629
|
+
x: result[0],
|
|
17630
|
+
y: result[1]
|
|
17631
|
+
};
|
|
17632
|
+
}
|
|
17631
17633
|
|
|
17632
|
-
|
|
17633
|
-
|
|
17634
|
-
|
|
17635
|
-
|
|
17636
|
-
|
|
17637
|
-
#
|
|
17638
|
-
#
|
|
17639
|
-
#
|
|
17640
|
-
#
|
|
17641
|
-
#
|
|
17642
|
-
#
|
|
17643
|
-
#
|
|
17644
|
-
|
|
17645
|
-
|
|
17646
|
-
|
|
17647
|
-
|
|
17648
|
-
|
|
17649
|
-
|
|
17650
|
-
|
|
17634
|
+
// src/scene/SceneNode.ts
|
|
17635
|
+
class SceneNode {
|
|
17636
|
+
static nextId = 1;
|
|
17637
|
+
id;
|
|
17638
|
+
label;
|
|
17639
|
+
#isActive = true;
|
|
17640
|
+
#layer = null;
|
|
17641
|
+
#parent = null;
|
|
17642
|
+
#key = null;
|
|
17643
|
+
#kids = [];
|
|
17644
|
+
#transform;
|
|
17645
|
+
#matrix = mat3.identity();
|
|
17646
|
+
#renderComponent = null;
|
|
17647
|
+
#size = null;
|
|
17648
|
+
#positionProxy;
|
|
17649
|
+
#scaleProxy;
|
|
17650
|
+
#cache = null;
|
|
17651
|
+
constructor(opts) {
|
|
17652
|
+
this.id = opts?.id ?? SceneNode.nextId++;
|
|
17653
|
+
if (opts?.rotation && opts?.rotationRadians) {
|
|
17654
|
+
throw new Error(`Cannot set both rotation and rotationRadians for node ${opts?.label ?? this.id}`);
|
|
17655
|
+
}
|
|
17656
|
+
this.#transform = {
|
|
17657
|
+
position: opts?.position ?? { x: 0, y: 0 },
|
|
17658
|
+
scale: { x: 1, y: 1 },
|
|
17659
|
+
size: opts?.size ?? { width: 1, height: 1 },
|
|
17660
|
+
rotation: opts?.rotationRadians ?? 0
|
|
17651
17661
|
};
|
|
17652
|
-
|
|
17653
|
-
|
|
17654
|
-
|
|
17655
|
-
|
|
17656
|
-
|
|
17657
|
-
|
|
17658
|
-
|
|
17659
|
-
|
|
17660
|
-
|
|
17661
|
-
|
|
17662
|
-
|
|
17663
|
-
|
|
17664
|
-
|
|
17665
|
-
this.#atlasSize = options.atlasSize;
|
|
17662
|
+
if (opts?.scale)
|
|
17663
|
+
this.scale = opts.scale;
|
|
17664
|
+
if (opts?.rotation)
|
|
17665
|
+
this.rotation = opts.rotation;
|
|
17666
|
+
this.#matrix = mat3.identity();
|
|
17667
|
+
this.#renderComponent = opts?.render ?? null;
|
|
17668
|
+
this.#layer = opts?.layer ?? null;
|
|
17669
|
+
this.#isActive = opts?.isActive ?? true;
|
|
17670
|
+
this.label = opts?.label ?? undefined;
|
|
17671
|
+
this.#size = opts?.size ?? null;
|
|
17672
|
+
this.#key = opts?.key ?? null;
|
|
17673
|
+
for (const kid of opts?.kids ?? []) {
|
|
17674
|
+
this.add(kid);
|
|
17666
17675
|
}
|
|
17667
|
-
|
|
17668
|
-
this.#
|
|
17669
|
-
|
|
17670
|
-
|
|
17671
|
-
|
|
17672
|
-
|
|
17673
|
-
|
|
17674
|
-
|
|
17676
|
+
const self = this;
|
|
17677
|
+
this.#positionProxy = {
|
|
17678
|
+
get x() {
|
|
17679
|
+
return self.#transform.position.x;
|
|
17680
|
+
},
|
|
17681
|
+
set x(value) {
|
|
17682
|
+
self.#transform.position.x = value;
|
|
17683
|
+
self.setDirty();
|
|
17684
|
+
},
|
|
17685
|
+
get y() {
|
|
17686
|
+
return self.#transform.position.y;
|
|
17687
|
+
},
|
|
17688
|
+
set y(value) {
|
|
17689
|
+
self.#transform.position.y = value;
|
|
17690
|
+
self.setDirty();
|
|
17691
|
+
}
|
|
17692
|
+
};
|
|
17693
|
+
this.#scaleProxy = {
|
|
17694
|
+
get x() {
|
|
17695
|
+
return self.#transform.scale.x;
|
|
17696
|
+
},
|
|
17697
|
+
set x(value) {
|
|
17698
|
+
self.#transform.scale.x = value;
|
|
17699
|
+
self.setDirty();
|
|
17700
|
+
},
|
|
17701
|
+
get y() {
|
|
17702
|
+
return self.#transform.scale.y;
|
|
17703
|
+
},
|
|
17704
|
+
set y(value) {
|
|
17705
|
+
self.#transform.scale.y = value;
|
|
17706
|
+
self.setDirty();
|
|
17707
|
+
}
|
|
17675
17708
|
};
|
|
17676
|
-
this.#writeInstance = options.writeInstance;
|
|
17677
|
-
}
|
|
17678
|
-
get color() {
|
|
17679
|
-
return this.#color;
|
|
17680
|
-
}
|
|
17681
|
-
set color(value) {
|
|
17682
|
-
this.#color = value;
|
|
17683
17709
|
}
|
|
17684
|
-
|
|
17685
|
-
|
|
17686
|
-
if (
|
|
17687
|
-
|
|
17710
|
+
add(kid, index) {
|
|
17711
|
+
kid.#parent = this;
|
|
17712
|
+
if (index === undefined) {
|
|
17713
|
+
this.#kids.push(kid);
|
|
17714
|
+
} else {
|
|
17715
|
+
this.#kids.splice(index, 0, kid);
|
|
17688
17716
|
}
|
|
17689
|
-
|
|
17717
|
+
kid.setDirty();
|
|
17718
|
+
return kid;
|
|
17690
17719
|
}
|
|
17691
|
-
|
|
17692
|
-
|
|
17720
|
+
get kids() {
|
|
17721
|
+
return this.#kids;
|
|
17693
17722
|
}
|
|
17694
|
-
get
|
|
17695
|
-
|
|
17696
|
-
mat3.scale(matrix, [this.size.width * this.#flip.x, this.size.height * this.#flip.y], matrix);
|
|
17697
|
-
return matrix;
|
|
17723
|
+
get children() {
|
|
17724
|
+
return this.#kids;
|
|
17698
17725
|
}
|
|
17699
|
-
get
|
|
17700
|
-
return this.#
|
|
17726
|
+
get transform() {
|
|
17727
|
+
return this.#transform;
|
|
17701
17728
|
}
|
|
17702
|
-
get
|
|
17703
|
-
return this.#
|
|
17729
|
+
get key() {
|
|
17730
|
+
return this.#key ?? "";
|
|
17704
17731
|
}
|
|
17705
|
-
get
|
|
17706
|
-
return this.#
|
|
17732
|
+
get parent() {
|
|
17733
|
+
return this.#parent;
|
|
17707
17734
|
}
|
|
17708
|
-
|
|
17709
|
-
|
|
17735
|
+
set position(value) {
|
|
17736
|
+
this.#transform.position = value;
|
|
17737
|
+
this.setDirty();
|
|
17710
17738
|
}
|
|
17711
|
-
|
|
17712
|
-
this.#
|
|
17739
|
+
get position() {
|
|
17740
|
+
return this.#positionProxy;
|
|
17741
|
+
}
|
|
17742
|
+
set x(value) {
|
|
17743
|
+
this.#transform.position.x = value;
|
|
17713
17744
|
this.setDirty();
|
|
17714
17745
|
}
|
|
17715
|
-
get
|
|
17716
|
-
return this.#
|
|
17746
|
+
get x() {
|
|
17747
|
+
return this.#transform.position.x;
|
|
17717
17748
|
}
|
|
17718
|
-
set
|
|
17719
|
-
this.#
|
|
17749
|
+
set y(value) {
|
|
17750
|
+
this.#transform.position.y = value;
|
|
17720
17751
|
this.setDirty();
|
|
17721
17752
|
}
|
|
17722
|
-
get
|
|
17723
|
-
return this.#
|
|
17753
|
+
get y() {
|
|
17754
|
+
return this.#transform.position.y;
|
|
17724
17755
|
}
|
|
17725
|
-
set
|
|
17726
|
-
this.#
|
|
17756
|
+
set rotation(value) {
|
|
17757
|
+
this.#transform.rotation = deg2rad(value);
|
|
17758
|
+
this.setDirty();
|
|
17727
17759
|
}
|
|
17728
|
-
get
|
|
17729
|
-
return this.#
|
|
17760
|
+
get rotation() {
|
|
17761
|
+
return rad2deg(this.#transform.rotation);
|
|
17730
17762
|
}
|
|
17731
|
-
get
|
|
17732
|
-
return this.#
|
|
17763
|
+
get rotationRadians() {
|
|
17764
|
+
return this.#transform.rotation;
|
|
17733
17765
|
}
|
|
17734
|
-
|
|
17735
|
-
|
|
17766
|
+
set rotationRadians(value) {
|
|
17767
|
+
this.#transform.rotation = value;
|
|
17768
|
+
this.setDirty();
|
|
17736
17769
|
}
|
|
17737
|
-
|
|
17738
|
-
|
|
17739
|
-
|
|
17740
|
-
|
|
17741
|
-
|
|
17742
|
-
|
|
17743
|
-
}
|
|
17744
|
-
|
|
17745
|
-
return this.#atlasSize;
|
|
17770
|
+
get scale() {
|
|
17771
|
+
return this.#scaleProxy;
|
|
17772
|
+
}
|
|
17773
|
+
set scale(value) {
|
|
17774
|
+
if (typeof value === "number") {
|
|
17775
|
+
this.#transform.scale = { x: value, y: value };
|
|
17776
|
+
} else {
|
|
17777
|
+
this.#transform.scale = value;
|
|
17746
17778
|
}
|
|
17747
|
-
|
|
17748
|
-
}
|
|
17749
|
-
function writeQuadInstance(node, array, offset) {
|
|
17750
|
-
if (!(node instanceof QuadNode)) {
|
|
17751
|
-
throw new Error("QuadNode.writeInstance can only be called on QuadNodes");
|
|
17779
|
+
this.setDirty();
|
|
17752
17780
|
}
|
|
17753
|
-
|
|
17754
|
-
|
|
17755
|
-
|
|
17756
|
-
if (node.textureId === PRIMITIVE_TEXTURE) {
|
|
17757
|
-
array.set([
|
|
17758
|
-
node.atlasCoords.uvOffset.x,
|
|
17759
|
-
node.atlasCoords.uvOffset.y,
|
|
17760
|
-
node.atlasCoords.uvScale.width,
|
|
17761
|
-
node.atlasCoords.uvScale.height
|
|
17762
|
-
], offset + 16);
|
|
17763
|
-
} else {
|
|
17764
|
-
const atlasSize = node.extra.atlasSize();
|
|
17765
|
-
array.set([
|
|
17766
|
-
node.atlasCoords.uvOffset.x + region.x / atlasSize.width,
|
|
17767
|
-
node.atlasCoords.uvOffset.y + region.y / atlasSize.height,
|
|
17768
|
-
region.width / atlasSize.width,
|
|
17769
|
-
region.height / atlasSize.height
|
|
17770
|
-
], offset + 16);
|
|
17781
|
+
set size(value) {
|
|
17782
|
+
this.#size = value;
|
|
17783
|
+
this.setDirty();
|
|
17771
17784
|
}
|
|
17772
|
-
|
|
17773
|
-
|
|
17774
|
-
|
|
17775
|
-
|
|
17776
|
-
|
|
17777
|
-
|
|
17778
|
-
|
|
17779
|
-
node.writeInstance?.(array, offset + 28);
|
|
17780
|
-
return 1;
|
|
17781
|
-
}
|
|
17782
|
-
|
|
17783
|
-
// src/scene/JumboQuadNode.ts
|
|
17784
|
-
var MAT3_SIZE = 12;
|
|
17785
|
-
var VEC4F_SIZE = 4;
|
|
17786
|
-
|
|
17787
|
-
class JumboQuadNode extends QuadNode {
|
|
17788
|
-
#tiles;
|
|
17789
|
-
#matrixPool;
|
|
17790
|
-
constructor(options, matrixPool) {
|
|
17791
|
-
assert(options.shader, "JumboQuadNode requires a shader to be explicitly provided");
|
|
17792
|
-
assert(options.tiles && options.tiles.length > 0, "JumboQuadNode requires at least one tile to be provided");
|
|
17793
|
-
options.render ??= {
|
|
17794
|
-
shader: options.shader,
|
|
17795
|
-
writeInstance: writeJumboQuadInstance
|
|
17796
|
-
};
|
|
17797
|
-
super({
|
|
17798
|
-
...options,
|
|
17799
|
-
atlasCoords: options.tiles[0].atlasCoords
|
|
17800
|
-
}, matrixPool);
|
|
17801
|
-
this.#matrixPool = matrixPool;
|
|
17802
|
-
this.#tiles = [];
|
|
17803
|
-
for (const tile of options.tiles) {
|
|
17804
|
-
assert(tile.atlasCoords, "JumboQuadNode requires atlas coords to be provided");
|
|
17805
|
-
assert(tile.size, "JumboQuadNode requires a size to be provided");
|
|
17806
|
-
this.#tiles.push({
|
|
17807
|
-
textureId: tile.textureId,
|
|
17808
|
-
offset: tile.offset,
|
|
17809
|
-
size: tile.size,
|
|
17810
|
-
atlasCoords: tile.atlasCoords
|
|
17811
|
-
});
|
|
17785
|
+
get size() {
|
|
17786
|
+
return this.#size;
|
|
17787
|
+
}
|
|
17788
|
+
get aspectRatio() {
|
|
17789
|
+
if (!this.#size) {
|
|
17790
|
+
console.warn("Attempted to get aspect ratio of a node with no ideal size");
|
|
17791
|
+
return 1;
|
|
17812
17792
|
}
|
|
17793
|
+
return this.#size.width / this.#size.height;
|
|
17813
17794
|
}
|
|
17814
|
-
get
|
|
17815
|
-
|
|
17795
|
+
get isActive() {
|
|
17796
|
+
if (!this.#cache?.isActive) {
|
|
17797
|
+
this.#cache ??= {};
|
|
17798
|
+
let parent = this;
|
|
17799
|
+
let isActive = this.#isActive;
|
|
17800
|
+
while (isActive && parent.#parent) {
|
|
17801
|
+
parent = parent.#parent;
|
|
17802
|
+
isActive = isActive && parent.#isActive;
|
|
17803
|
+
}
|
|
17804
|
+
this.#cache.isActive = isActive;
|
|
17805
|
+
}
|
|
17806
|
+
return this.#cache.isActive;
|
|
17816
17807
|
}
|
|
17817
|
-
|
|
17818
|
-
|
|
17808
|
+
set isActive(value) {
|
|
17809
|
+
this.#isActive = value;
|
|
17810
|
+
this.setDirty();
|
|
17819
17811
|
}
|
|
17820
|
-
|
|
17821
|
-
|
|
17822
|
-
|
|
17823
|
-
|
|
17824
|
-
|
|
17825
|
-
|
|
17826
|
-
|
|
17827
|
-
|
|
17828
|
-
|
|
17829
|
-
|
|
17830
|
-
|
|
17831
|
-
|
|
17832
|
-
|
|
17833
|
-
|
|
17834
|
-
|
|
17835
|
-
|
|
17836
|
-
|
|
17837
|
-
], matrix);
|
|
17838
|
-
mat3.scale(matrix, [
|
|
17839
|
-
tile.size.width * proportionalSize.width * (this.flipX ? -1 : 1),
|
|
17840
|
-
tile.size.height * proportionalSize.height * (this.flipY ? -1 : 1)
|
|
17841
|
-
], matrix);
|
|
17842
|
-
return matrix;
|
|
17812
|
+
get layer() {
|
|
17813
|
+
if (this.#layer != null) {
|
|
17814
|
+
return this.#layer;
|
|
17815
|
+
}
|
|
17816
|
+
if (!this.#cache?.layer) {
|
|
17817
|
+
this.#cache ??= {};
|
|
17818
|
+
let parent = this;
|
|
17819
|
+
while (parent.#parent) {
|
|
17820
|
+
parent = parent.#parent;
|
|
17821
|
+
if (parent.hasExplicitLayer) {
|
|
17822
|
+
this.#cache.layer = parent.#layer;
|
|
17823
|
+
return this.#cache.layer;
|
|
17824
|
+
}
|
|
17825
|
+
}
|
|
17826
|
+
this.#cache.layer = 0;
|
|
17827
|
+
}
|
|
17828
|
+
return this.#cache.layer;
|
|
17843
17829
|
}
|
|
17844
|
-
|
|
17845
|
-
|
|
17846
|
-
if (!(node instanceof JumboQuadNode)) {
|
|
17847
|
-
throw new Error("JumboQuadNode.writeJumboQuadInstance can only be called on JumboQuadNodes");
|
|
17830
|
+
get hasExplicitLayer() {
|
|
17831
|
+
return this.#layer != null;
|
|
17848
17832
|
}
|
|
17849
|
-
|
|
17850
|
-
|
|
17851
|
-
|
|
17852
|
-
const matrix = node.getTileMatrix(tile);
|
|
17853
|
-
array.set(matrix, offset + tileOffset);
|
|
17854
|
-
tileOffset += MAT3_SIZE;
|
|
17855
|
-
array.set([node.color.r, node.color.g, node.color.b, node.color.a], offset + tileOffset);
|
|
17856
|
-
tileOffset += VEC4F_SIZE;
|
|
17857
|
-
array.set([
|
|
17858
|
-
coord.uvOffset.x,
|
|
17859
|
-
coord.uvOffset.y,
|
|
17860
|
-
coord.uvScale.width,
|
|
17861
|
-
coord.uvScale.height
|
|
17862
|
-
], offset + tileOffset);
|
|
17863
|
-
tileOffset += VEC4F_SIZE;
|
|
17864
|
-
const cropRatio = !coord.uvScaleCropped ? { width: 1, height: 1 } : {
|
|
17865
|
-
width: coord.uvScaleCropped.width / coord.uvScale.width,
|
|
17866
|
-
height: coord.uvScaleCropped.height / coord.uvScale.height
|
|
17867
|
-
};
|
|
17868
|
-
array.set([
|
|
17869
|
-
tile.atlasCoords.cropOffset.x / 2 / (tile.atlasCoords.originalSize.width || 1),
|
|
17870
|
-
tile.atlasCoords.cropOffset.y / 2 / (tile.atlasCoords.originalSize.height || 1),
|
|
17871
|
-
cropRatio.width,
|
|
17872
|
-
cropRatio.height
|
|
17873
|
-
], offset + tileOffset);
|
|
17874
|
-
tileOffset += VEC4F_SIZE;
|
|
17875
|
-
new DataView(array.buffer).setUint32(array.byteOffset + (offset + tileOffset) * Float32Array.BYTES_PER_ELEMENT, coord.atlasIndex, true);
|
|
17876
|
-
tileOffset += VEC4F_SIZE;
|
|
17833
|
+
set layer(value) {
|
|
17834
|
+
this.#layer = value;
|
|
17835
|
+
this.setDirty();
|
|
17877
17836
|
}
|
|
17878
|
-
|
|
17879
|
-
|
|
17880
|
-
}
|
|
17881
|
-
|
|
17882
|
-
// src/utils/error.ts
|
|
17883
|
-
var warnings = new Map;
|
|
17884
|
-
function warnOnce(key, msg) {
|
|
17885
|
-
if (warnings.has(key)) {
|
|
17886
|
-
return;
|
|
17837
|
+
get renderComponent() {
|
|
17838
|
+
return this.#renderComponent;
|
|
17887
17839
|
}
|
|
17888
|
-
|
|
17889
|
-
|
|
17890
|
-
}
|
|
17891
|
-
|
|
17892
|
-
|
|
17893
|
-
|
|
17894
|
-
|
|
17895
|
-
json;
|
|
17896
|
-
imageBitmap;
|
|
17897
|
-
name;
|
|
17898
|
-
charset;
|
|
17899
|
-
charCount;
|
|
17900
|
-
lineHeight;
|
|
17901
|
-
charBuffer;
|
|
17902
|
-
#kernings;
|
|
17903
|
-
#chars;
|
|
17904
|
-
#fallbackCharCode;
|
|
17905
|
-
constructor(id, json, imageBitmap) {
|
|
17906
|
-
this.id = id;
|
|
17907
|
-
this.json = json;
|
|
17908
|
-
this.imageBitmap = imageBitmap;
|
|
17909
|
-
const charArray = Object.values(json.chars);
|
|
17910
|
-
this.charCount = charArray.length;
|
|
17911
|
-
this.lineHeight = json.common.lineHeight;
|
|
17912
|
-
this.charset = json.info.charset;
|
|
17913
|
-
this.name = json.info.face;
|
|
17914
|
-
this.#kernings = new Map;
|
|
17915
|
-
if (json.kernings) {
|
|
17916
|
-
for (const kearning of json.kernings) {
|
|
17917
|
-
let charKerning = this.#kernings.get(kearning.first);
|
|
17918
|
-
if (!charKerning) {
|
|
17919
|
-
charKerning = new Map;
|
|
17920
|
-
this.#kernings.set(kearning.first, charKerning);
|
|
17921
|
-
}
|
|
17922
|
-
charKerning.set(kearning.second, kearning.amount);
|
|
17840
|
+
get matrix() {
|
|
17841
|
+
if (!this.#cache?.matrix) {
|
|
17842
|
+
this.#cache ??= {};
|
|
17843
|
+
if (this.#parent) {
|
|
17844
|
+
mat3.clone(this.#parent.matrix, this.#matrix);
|
|
17845
|
+
} else {
|
|
17846
|
+
mat3.identity(this.#matrix);
|
|
17923
17847
|
}
|
|
17848
|
+
this.#cache.matrix = createModelMatrix(this.transform, this.#matrix);
|
|
17924
17849
|
}
|
|
17925
|
-
this.#
|
|
17926
|
-
const charCount = Object.values(json.chars).length;
|
|
17927
|
-
this.charBuffer = new Float32Array(charCount * 8);
|
|
17928
|
-
let offset = 0;
|
|
17929
|
-
const u3 = 1 / json.common.scaleW;
|
|
17930
|
-
const v3 = 1 / json.common.scaleH;
|
|
17931
|
-
for (const [i3, char] of json.chars.entries()) {
|
|
17932
|
-
this.#chars.set(char.id, char);
|
|
17933
|
-
this.#chars.get(char.id).charIndex = i3;
|
|
17934
|
-
this.charBuffer[offset] = char.x * u3;
|
|
17935
|
-
this.charBuffer[offset + 1] = char.y * v3;
|
|
17936
|
-
this.charBuffer[offset + 2] = char.width * u3;
|
|
17937
|
-
this.charBuffer[offset + 3] = char.height * v3;
|
|
17938
|
-
this.charBuffer[offset + 4] = char.width;
|
|
17939
|
-
this.charBuffer[offset + 5] = char.height;
|
|
17940
|
-
this.charBuffer[offset + 6] = char.xoffset;
|
|
17941
|
-
this.charBuffer[offset + 7] = -char.yoffset;
|
|
17942
|
-
offset += 8;
|
|
17943
|
-
}
|
|
17850
|
+
return this.#cache.matrix;
|
|
17944
17851
|
}
|
|
17945
|
-
|
|
17946
|
-
|
|
17947
|
-
|
|
17948
|
-
const
|
|
17949
|
-
|
|
17950
|
-
|
|
17852
|
+
get bounds() {
|
|
17853
|
+
if (!this.#cache?.bounds) {
|
|
17854
|
+
this.#cache ??= {};
|
|
17855
|
+
const height = this.size?.height ?? 0;
|
|
17856
|
+
const width = this.size?.width ?? 0;
|
|
17857
|
+
const corners = [
|
|
17858
|
+
vec2.transformMat3([-width / 2, height / 2], this.matrix),
|
|
17859
|
+
vec2.transformMat3([width / 2, height / 2], this.matrix),
|
|
17860
|
+
vec2.transformMat3([-width / 2, -height / 2], this.matrix),
|
|
17861
|
+
vec2.transformMat3([width / 2, -height / 2], this.matrix)
|
|
17862
|
+
];
|
|
17863
|
+
const center = vec2.transformMat3([0, 0], this.matrix);
|
|
17864
|
+
const xValues = corners.map((c3) => c3[0]);
|
|
17865
|
+
const yValues = corners.map((c3) => c3[1]);
|
|
17866
|
+
this.#cache.bounds = {
|
|
17867
|
+
x: center[0],
|
|
17868
|
+
y: center[1],
|
|
17869
|
+
left: Math.min(xValues[0], xValues[1], xValues[2], xValues[3]),
|
|
17870
|
+
right: Math.max(xValues[0], xValues[1], xValues[2], xValues[3]),
|
|
17871
|
+
top: Math.max(yValues[0], yValues[1], yValues[2], yValues[3]),
|
|
17872
|
+
bottom: Math.min(yValues[0], yValues[1], yValues[2], yValues[3])
|
|
17873
|
+
};
|
|
17951
17874
|
}
|
|
17952
|
-
return
|
|
17875
|
+
return this.#cache.bounds;
|
|
17953
17876
|
}
|
|
17954
|
-
|
|
17955
|
-
|
|
17956
|
-
|
|
17957
|
-
|
|
17958
|
-
|
|
17959
|
-
|
|
17960
|
-
|
|
17961
|
-
|
|
17962
|
-
|
|
17877
|
+
setBounds(bounds) {
|
|
17878
|
+
if (bounds.left !== undefined)
|
|
17879
|
+
this.left = bounds.left;
|
|
17880
|
+
if (bounds.right !== undefined)
|
|
17881
|
+
this.right = bounds.right;
|
|
17882
|
+
if (bounds.top !== undefined)
|
|
17883
|
+
this.top = bounds.top;
|
|
17884
|
+
if (bounds.bottom !== undefined)
|
|
17885
|
+
this.bottom = bounds.bottom;
|
|
17886
|
+
if (bounds.x !== undefined)
|
|
17887
|
+
this.centerX = bounds.x;
|
|
17888
|
+
if (bounds.y !== undefined)
|
|
17889
|
+
this.centerY = bounds.y;
|
|
17890
|
+
return this;
|
|
17963
17891
|
}
|
|
17964
|
-
|
|
17965
|
-
|
|
17966
|
-
|
|
17967
|
-
|
|
17968
|
-
|
|
17969
|
-
|
|
17970
|
-
|
|
17971
|
-
|
|
17972
|
-
|
|
17973
|
-
|
|
17892
|
+
set left(value) {
|
|
17893
|
+
this.#adjustWorldPosition([value - this.bounds.left, 0]);
|
|
17894
|
+
}
|
|
17895
|
+
set bottom(value) {
|
|
17896
|
+
this.#adjustWorldPosition([0, value - this.bounds.bottom]);
|
|
17897
|
+
}
|
|
17898
|
+
set top(value) {
|
|
17899
|
+
this.#adjustWorldPosition([0, value - this.bounds.top]);
|
|
17900
|
+
}
|
|
17901
|
+
set right(value) {
|
|
17902
|
+
this.#adjustWorldPosition([value - this.bounds.right, 0]);
|
|
17903
|
+
}
|
|
17904
|
+
set centerX(value) {
|
|
17905
|
+
this.#adjustWorldPosition([value - this.bounds.x, 0]);
|
|
17906
|
+
}
|
|
17907
|
+
set centerY(value) {
|
|
17908
|
+
this.#adjustWorldPosition([0, value - this.bounds.y]);
|
|
17909
|
+
}
|
|
17910
|
+
delete() {
|
|
17911
|
+
this.#parent?.remove(this);
|
|
17912
|
+
for (const child of this.#kids) {
|
|
17913
|
+
child.delete();
|
|
17974
17914
|
}
|
|
17975
|
-
|
|
17976
|
-
|
|
17977
|
-
|
|
17978
|
-
|
|
17915
|
+
this.#kids = [];
|
|
17916
|
+
this.#isActive = false;
|
|
17917
|
+
this.#layer = null;
|
|
17918
|
+
this.#renderComponent = null;
|
|
17979
17919
|
}
|
|
17980
|
-
|
|
17981
|
-
const
|
|
17982
|
-
if (
|
|
17983
|
-
this
|
|
17984
|
-
} else {
|
|
17985
|
-
const fallbackCode = this.#chars.keys().toArray()[0];
|
|
17986
|
-
console.warn(`${character} character does not exist in font ${this.name} defaulting to "${this.#chars.get(fallbackCode)?.char}".`);
|
|
17987
|
-
this.#fallbackCharCode = fallbackCode;
|
|
17920
|
+
remove(kid) {
|
|
17921
|
+
const childIndex = this.#kids.findIndex((child) => child.id === kid.id);
|
|
17922
|
+
if (childIndex <= -1) {
|
|
17923
|
+
throw new Error(`${kid.label ?? kid.id} is not a child of ${this.label ?? this.id}`);
|
|
17988
17924
|
}
|
|
17925
|
+
this.#kids.splice(childIndex, 1);
|
|
17926
|
+
kid.#parent = null;
|
|
17927
|
+
kid.setDirty();
|
|
17928
|
+
}
|
|
17929
|
+
#adjustWorldPosition(delta) {
|
|
17930
|
+
const inverseMatrix = mat3.inverse(this.#parent?.matrix ?? mat3.identity());
|
|
17931
|
+
inverseMatrix[8] = inverseMatrix[9] = 0;
|
|
17932
|
+
const localDelta = vec2.transformMat3(delta, inverseMatrix);
|
|
17933
|
+
this.#transform.position.x += localDelta[0];
|
|
17934
|
+
this.#transform.position.y += localDelta[1];
|
|
17935
|
+
this.setDirty();
|
|
17936
|
+
}
|
|
17937
|
+
setDirty() {
|
|
17938
|
+
this.#cache = null;
|
|
17939
|
+
this.#kids.forEach((kid) => kid.setDirty());
|
|
17940
|
+
}
|
|
17941
|
+
static parse(json) {
|
|
17942
|
+
const obj = JSON.parse(json, reviver);
|
|
17943
|
+
return new SceneNode(obj);
|
|
17944
|
+
}
|
|
17945
|
+
toJSON() {
|
|
17946
|
+
return {
|
|
17947
|
+
id: this.id,
|
|
17948
|
+
label: this.label,
|
|
17949
|
+
transform: this.#transform,
|
|
17950
|
+
layer: this.#layer,
|
|
17951
|
+
isActive: this.#isActive,
|
|
17952
|
+
kids: this.#kids,
|
|
17953
|
+
render: this.#renderComponent
|
|
17954
|
+
};
|
|
17989
17955
|
}
|
|
17990
17956
|
}
|
|
17991
|
-
|
|
17992
|
-
|
|
17993
|
-
|
|
17994
|
-
function shapeText(font, text, blockSize, fontSize, formatting, textArray, initialFloatOffset = 0, debug = false) {
|
|
17995
|
-
let offset = initialFloatOffset;
|
|
17996
|
-
const measurements = measureText(font, text, formatting.wordWrap);
|
|
17997
|
-
const alignment = formatting.align || "left";
|
|
17998
|
-
const em2px = fontSize / font.lineHeight;
|
|
17999
|
-
const hackHasExplicitBlock = blockSize.width !== measurements.width;
|
|
18000
|
-
let debugData = null;
|
|
18001
|
-
if (debug) {
|
|
18002
|
-
debugData = [];
|
|
17957
|
+
function reviver(key, value) {
|
|
17958
|
+
if (key === "kids") {
|
|
17959
|
+
return value.map((kid) => new SceneNode(kid));
|
|
18003
17960
|
}
|
|
18004
|
-
|
|
18005
|
-
|
|
18006
|
-
|
|
18007
|
-
|
|
18008
|
-
|
|
18009
|
-
|
|
18010
|
-
|
|
18011
|
-
|
|
18012
|
-
|
|
18013
|
-
} else if (alignment === "left") {
|
|
18014
|
-
const blockSizeEm = blockSize.width / em2px;
|
|
18015
|
-
lineOffset = hackHasExplicitBlock ? -blockSizeEm / 2 : -measurements.width / 2;
|
|
18016
|
-
}
|
|
18017
|
-
if (debug && debugData) {
|
|
18018
|
-
debugData.push({
|
|
18019
|
-
line: glyph.line,
|
|
18020
|
-
word: word.glyphs.map((g3) => g3.char.char).join(""),
|
|
18021
|
-
glyph: glyph.char.char,
|
|
18022
|
-
startX: word.startX,
|
|
18023
|
-
glyphX: glyph.offset[0],
|
|
18024
|
-
advance: glyph.char.xadvance,
|
|
18025
|
-
lineOffset,
|
|
18026
|
-
startY: word.startY,
|
|
18027
|
-
glyphY: glyph.offset[1]
|
|
18028
|
-
});
|
|
18029
|
-
}
|
|
18030
|
-
textArray[offset] = word.startX + glyph.offset[0] + lineOffset;
|
|
18031
|
-
textArray[offset + 1] = word.startY + glyph.offset[1];
|
|
18032
|
-
textArray[offset + 2] = glyph.char.charIndex;
|
|
18033
|
-
offset += 4;
|
|
17961
|
+
if (Array.isArray(value) && value.every((v3) => typeof v3 === "number")) {
|
|
17962
|
+
if (value.length === 2) {
|
|
17963
|
+
return value;
|
|
17964
|
+
}
|
|
17965
|
+
if (value.length === 3) {
|
|
17966
|
+
return value;
|
|
17967
|
+
}
|
|
17968
|
+
if (value.length === 4) {
|
|
17969
|
+
return value;
|
|
18034
17970
|
}
|
|
18035
17971
|
}
|
|
18036
|
-
|
|
18037
|
-
console.table(debugData);
|
|
18038
|
-
}
|
|
18039
|
-
}
|
|
18040
|
-
function measureText(font, text, wordWrap) {
|
|
18041
|
-
let maxWidth = 0;
|
|
18042
|
-
const lineWidths = [];
|
|
18043
|
-
let textOffsetX = 0;
|
|
18044
|
-
let textOffsetY = 0;
|
|
18045
|
-
let line = 0;
|
|
18046
|
-
let printedCharCount = 0;
|
|
18047
|
-
let nextCharCode = text.charCodeAt(0);
|
|
18048
|
-
let word = { glyphs: [], width: 0, startX: 0, startY: 0 };
|
|
18049
|
-
const words = [];
|
|
18050
|
-
for (let i3 = 0;i3 < text.length; i3++) {
|
|
18051
|
-
const isLastLetter = i3 === text.length - 1;
|
|
18052
|
-
const charCode = nextCharCode;
|
|
18053
|
-
nextCharCode = i3 < text.length - 1 ? text.charCodeAt(i3 + 1) : -1;
|
|
18054
|
-
switch (charCode) {
|
|
18055
|
-
case 9 /* HorizontalTab */:
|
|
18056
|
-
insertSpaces(TAB_SPACES);
|
|
18057
|
-
break;
|
|
18058
|
-
case 10 /* Newline */:
|
|
18059
|
-
flushLine();
|
|
18060
|
-
flushWord();
|
|
18061
|
-
break;
|
|
18062
|
-
case 13 /* CarriageReturn */:
|
|
18063
|
-
break;
|
|
18064
|
-
case 32 /* Space */:
|
|
18065
|
-
insertSpaces(1);
|
|
18066
|
-
break;
|
|
18067
|
-
default: {
|
|
18068
|
-
const advance = font.getXAdvance(charCode, nextCharCode);
|
|
18069
|
-
if (wordWrap && wordWrap.breakOn === "character" && textOffsetX + advance > wordWrap.emWidth) {
|
|
18070
|
-
if (word.startX === 0) {
|
|
18071
|
-
flushWord();
|
|
18072
|
-
} else {
|
|
18073
|
-
lineWidths.push(textOffsetX - word.width);
|
|
18074
|
-
line++;
|
|
18075
|
-
maxWidth = Math.max(maxWidth, textOffsetX);
|
|
18076
|
-
textOffsetX = word.width;
|
|
18077
|
-
textOffsetY -= font.lineHeight;
|
|
18078
|
-
word.startX = 0;
|
|
18079
|
-
word.startY = textOffsetY;
|
|
18080
|
-
word.glyphs.forEach((g3) => {
|
|
18081
|
-
g3.line = line;
|
|
18082
|
-
});
|
|
18083
|
-
}
|
|
18084
|
-
}
|
|
18085
|
-
word.glyphs.push({
|
|
18086
|
-
char: font.getChar(charCode),
|
|
18087
|
-
offset: [word.width, 0],
|
|
18088
|
-
line
|
|
18089
|
-
});
|
|
18090
|
-
if (isLastLetter) {
|
|
18091
|
-
flushWord();
|
|
18092
|
-
}
|
|
18093
|
-
word.width += advance;
|
|
18094
|
-
textOffsetX += advance;
|
|
18095
|
-
}
|
|
18096
|
-
}
|
|
18097
|
-
}
|
|
18098
|
-
lineWidths.push(textOffsetX);
|
|
18099
|
-
maxWidth = Math.max(maxWidth, textOffsetX);
|
|
18100
|
-
const lineCount = lineWidths.length;
|
|
18101
|
-
return {
|
|
18102
|
-
width: maxWidth,
|
|
18103
|
-
height: lineCount * font.lineHeight,
|
|
18104
|
-
lineWidths,
|
|
18105
|
-
lineCount,
|
|
18106
|
-
printedCharCount,
|
|
18107
|
-
words
|
|
18108
|
-
};
|
|
18109
|
-
function flushWord() {
|
|
18110
|
-
printedCharCount += word.glyphs.length;
|
|
18111
|
-
words.push(word);
|
|
18112
|
-
word = {
|
|
18113
|
-
glyphs: [],
|
|
18114
|
-
width: 0,
|
|
18115
|
-
startX: textOffsetX,
|
|
18116
|
-
startY: textOffsetY
|
|
18117
|
-
};
|
|
18118
|
-
}
|
|
18119
|
-
function flushLine() {
|
|
18120
|
-
lineWidths.push(textOffsetX);
|
|
18121
|
-
line++;
|
|
18122
|
-
maxWidth = Math.max(maxWidth, textOffsetX);
|
|
18123
|
-
textOffsetX = 0;
|
|
18124
|
-
textOffsetY -= font.lineHeight;
|
|
18125
|
-
}
|
|
18126
|
-
function insertSpaces(spaces) {
|
|
18127
|
-
if (spaces < 1)
|
|
18128
|
-
spaces = 1;
|
|
18129
|
-
textOffsetX += font.getXAdvance(32 /* Space */) * spaces;
|
|
18130
|
-
if (wordWrap?.breakOn === "word" && textOffsetX >= wordWrap.emWidth) {
|
|
18131
|
-
flushLine();
|
|
18132
|
-
}
|
|
18133
|
-
flushWord();
|
|
18134
|
-
}
|
|
18135
|
-
}
|
|
18136
|
-
function findLargestFontSize(font, text, size, formatting) {
|
|
18137
|
-
if (!formatting.fontSize) {
|
|
18138
|
-
throw new Error("fontSize is required for shrinkToFit");
|
|
18139
|
-
}
|
|
18140
|
-
if (!formatting.shrinkToFit) {
|
|
18141
|
-
throw new Error("shrinkToFit is required for findLargestFontSize");
|
|
18142
|
-
}
|
|
18143
|
-
const minSize = formatting.shrinkToFit.minFontSize;
|
|
18144
|
-
const maxSize = formatting.shrinkToFit.maxFontSize ?? formatting.fontSize;
|
|
18145
|
-
const maxLines = formatting.shrinkToFit.maxLines ?? Number.POSITIVE_INFINITY;
|
|
18146
|
-
const threshold = 0.5;
|
|
18147
|
-
let low = minSize;
|
|
18148
|
-
let high = maxSize;
|
|
18149
|
-
while (high - low > threshold) {
|
|
18150
|
-
const testSize = (low + high) / 2;
|
|
18151
|
-
const testMeasure = measureText(font, text, formatting.wordWrap);
|
|
18152
|
-
const padding = formatting.shrinkToFit.padding ?? 0;
|
|
18153
|
-
const scaledWidth = testMeasure.width * (testSize / font.lineHeight);
|
|
18154
|
-
const scaledHeight = testMeasure.height * (testSize / font.lineHeight);
|
|
18155
|
-
const fitsWidth = scaledWidth <= size.width - size.width * padding;
|
|
18156
|
-
const fitsHeight = scaledHeight <= size.height - size.height * padding;
|
|
18157
|
-
const fitsLines = testMeasure.lineCount <= maxLines;
|
|
18158
|
-
if (fitsWidth && fitsHeight && fitsLines) {
|
|
18159
|
-
low = testSize;
|
|
18160
|
-
} else {
|
|
18161
|
-
high = testSize;
|
|
18162
|
-
}
|
|
18163
|
-
}
|
|
18164
|
-
return low;
|
|
17972
|
+
return value;
|
|
18165
17973
|
}
|
|
18166
17974
|
|
|
18167
17975
|
// src/scene/TextNode.ts
|
|
@@ -18222,81 +18030,6 @@ class TextNode extends SceneNode {
|
|
|
18222
18030
|
}
|
|
18223
18031
|
}
|
|
18224
18032
|
|
|
18225
|
-
// src/backends/webgl2/WebGLFontPipeline.ts
|
|
18226
|
-
class WebGLFontPipeline2 {
|
|
18227
|
-
font;
|
|
18228
|
-
fontTexture;
|
|
18229
|
-
charDataTexture;
|
|
18230
|
-
textBufferTexture;
|
|
18231
|
-
maxCharCount;
|
|
18232
|
-
lineHeight;
|
|
18233
|
-
#gl;
|
|
18234
|
-
constructor(gl, font, fontTexture, charDataTexture, textBufferTexture, maxCharCount) {
|
|
18235
|
-
this.#gl = gl;
|
|
18236
|
-
this.font = font;
|
|
18237
|
-
this.fontTexture = fontTexture;
|
|
18238
|
-
this.charDataTexture = charDataTexture;
|
|
18239
|
-
this.textBufferTexture = textBufferTexture;
|
|
18240
|
-
this.maxCharCount = maxCharCount;
|
|
18241
|
-
this.lineHeight = font.lineHeight;
|
|
18242
|
-
}
|
|
18243
|
-
static create(gl, font, maxCharCount) {
|
|
18244
|
-
const fontTexture = gl.createTexture();
|
|
18245
|
-
assert(fontTexture, "Failed to create font texture");
|
|
18246
|
-
gl.bindTexture(gl.TEXTURE_2D, fontTexture);
|
|
18247
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
18248
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
18249
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
18250
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
18251
|
-
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, font.imageBitmap);
|
|
18252
|
-
const charDataTexture = gl.createTexture();
|
|
18253
|
-
assert(charDataTexture, "Failed to create char data texture");
|
|
18254
|
-
gl.bindTexture(gl.TEXTURE_2D, charDataTexture);
|
|
18255
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
18256
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
18257
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
18258
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
18259
|
-
const charCount = font.charCount;
|
|
18260
|
-
const charTextureWidth = charCount * 2;
|
|
18261
|
-
const charTextureData = new Float32Array(charTextureWidth * 4);
|
|
18262
|
-
for (let i3 = 0;i3 < charCount; i3++) {
|
|
18263
|
-
const srcOffset = i3 * 8;
|
|
18264
|
-
const dstOffset0 = i3 * 2 * 4;
|
|
18265
|
-
const dstOffset1 = (i3 * 2 + 1) * 4;
|
|
18266
|
-
charTextureData[dstOffset0] = font.charBuffer[srcOffset];
|
|
18267
|
-
charTextureData[dstOffset0 + 1] = font.charBuffer[srcOffset + 1];
|
|
18268
|
-
charTextureData[dstOffset0 + 2] = font.charBuffer[srcOffset + 2];
|
|
18269
|
-
charTextureData[dstOffset0 + 3] = font.charBuffer[srcOffset + 3];
|
|
18270
|
-
charTextureData[dstOffset1] = font.charBuffer[srcOffset + 4];
|
|
18271
|
-
charTextureData[dstOffset1 + 1] = font.charBuffer[srcOffset + 5];
|
|
18272
|
-
charTextureData[dstOffset1 + 2] = font.charBuffer[srcOffset + 6];
|
|
18273
|
-
charTextureData[dstOffset1 + 3] = font.charBuffer[srcOffset + 7];
|
|
18274
|
-
}
|
|
18275
|
-
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA32F, charTextureWidth, 1, 0, gl.RGBA, gl.FLOAT, charTextureData);
|
|
18276
|
-
const textBufferTexture = gl.createTexture();
|
|
18277
|
-
assert(textBufferTexture, "Failed to create text buffer texture");
|
|
18278
|
-
gl.bindTexture(gl.TEXTURE_2D, textBufferTexture);
|
|
18279
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
18280
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
18281
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
18282
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
18283
|
-
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA32F, maxCharCount, 1, 0, gl.RGBA, gl.FLOAT, null);
|
|
18284
|
-
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
18285
|
-
return new WebGLFontPipeline2(gl, font, fontTexture, charDataTexture, textBufferTexture, maxCharCount);
|
|
18286
|
-
}
|
|
18287
|
-
updateTextBuffer(data, glyphCount) {
|
|
18288
|
-
const gl = this.#gl;
|
|
18289
|
-
gl.bindTexture(gl.TEXTURE_2D, this.textBufferTexture);
|
|
18290
|
-
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, glyphCount, 1, gl.RGBA, gl.FLOAT, data);
|
|
18291
|
-
}
|
|
18292
|
-
destroy() {
|
|
18293
|
-
const gl = this.#gl;
|
|
18294
|
-
gl.deleteTexture(this.fontTexture);
|
|
18295
|
-
gl.deleteTexture(this.charDataTexture);
|
|
18296
|
-
gl.deleteTexture(this.textBufferTexture);
|
|
18297
|
-
}
|
|
18298
|
-
}
|
|
18299
|
-
|
|
18300
18033
|
// src/backends/webgl2/glsl/text.glsl.ts
|
|
18301
18034
|
var vertexShader2 = `#version 300 es
|
|
18302
18035
|
precision highp float;
|
|
@@ -18421,7 +18154,7 @@ void main() {
|
|
|
18421
18154
|
`;
|
|
18422
18155
|
|
|
18423
18156
|
// src/backends/webgl2/WebGLTextShader.ts
|
|
18424
|
-
class
|
|
18157
|
+
class WebGLTextShader {
|
|
18425
18158
|
label = "text";
|
|
18426
18159
|
code = fragmentShader2;
|
|
18427
18160
|
font;
|
|
@@ -18743,7 +18476,7 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4f {
|
|
|
18743
18476
|
`;
|
|
18744
18477
|
|
|
18745
18478
|
// src/backends/webgpu/FontPipeline.ts
|
|
18746
|
-
class
|
|
18479
|
+
class FontPipeline {
|
|
18747
18480
|
pipeline;
|
|
18748
18481
|
font;
|
|
18749
18482
|
fontBindGroup;
|
|
@@ -18806,7 +18539,7 @@ class FontPipeline2 {
|
|
|
18806
18539
|
}
|
|
18807
18540
|
]
|
|
18808
18541
|
});
|
|
18809
|
-
return new
|
|
18542
|
+
return new FontPipeline(pipeline, font, fontBindGroup, maxCharCount);
|
|
18810
18543
|
}
|
|
18811
18544
|
}
|
|
18812
18545
|
function pipelinePromise(device, colorFormat, label) {
|
|
@@ -18852,70 +18585,550 @@ function pipelinePromise(device, colorFormat, label) {
|
|
|
18852
18585
|
}
|
|
18853
18586
|
});
|
|
18854
18587
|
}
|
|
18855
|
-
if (typeof GPUShaderStage === "undefined") {
|
|
18856
|
-
globalThis.GPUShaderStage = {
|
|
18857
|
-
VERTEX: 1,
|
|
18858
|
-
FRAGMENT: 2,
|
|
18859
|
-
COMPUTE: 4
|
|
18860
|
-
};
|
|
18588
|
+
if (typeof GPUShaderStage === "undefined") {
|
|
18589
|
+
globalThis.GPUShaderStage = {
|
|
18590
|
+
VERTEX: 1,
|
|
18591
|
+
FRAGMENT: 2,
|
|
18592
|
+
COMPUTE: 4
|
|
18593
|
+
};
|
|
18594
|
+
}
|
|
18595
|
+
var fontBindGroupLayout = {
|
|
18596
|
+
label: "MSDF font group layout",
|
|
18597
|
+
entries: [
|
|
18598
|
+
{
|
|
18599
|
+
binding: 0,
|
|
18600
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
18601
|
+
texture: {}
|
|
18602
|
+
},
|
|
18603
|
+
{
|
|
18604
|
+
binding: 1,
|
|
18605
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
18606
|
+
sampler: {}
|
|
18607
|
+
},
|
|
18608
|
+
{
|
|
18609
|
+
binding: 2,
|
|
18610
|
+
visibility: GPUShaderStage.VERTEX,
|
|
18611
|
+
buffer: { type: "read-only-storage" }
|
|
18612
|
+
},
|
|
18613
|
+
{
|
|
18614
|
+
binding: 3,
|
|
18615
|
+
visibility: GPUShaderStage.VERTEX,
|
|
18616
|
+
buffer: {}
|
|
18617
|
+
}
|
|
18618
|
+
]
|
|
18619
|
+
};
|
|
18620
|
+
var engineUniformBindGroupLayout = {
|
|
18621
|
+
label: "Uniform bind group",
|
|
18622
|
+
entries: [
|
|
18623
|
+
{
|
|
18624
|
+
binding: 0,
|
|
18625
|
+
visibility: GPUShaderStage.VERTEX,
|
|
18626
|
+
buffer: {}
|
|
18627
|
+
}
|
|
18628
|
+
]
|
|
18629
|
+
};
|
|
18630
|
+
var sampler = {
|
|
18631
|
+
label: "MSDF text sampler",
|
|
18632
|
+
minFilter: "linear",
|
|
18633
|
+
magFilter: "linear",
|
|
18634
|
+
mipmapFilter: "linear",
|
|
18635
|
+
maxAnisotropy: 16
|
|
18636
|
+
};
|
|
18637
|
+
var textUniformBindGroupLayout = {
|
|
18638
|
+
label: "MSDF text block uniform",
|
|
18639
|
+
entries: [
|
|
18640
|
+
{
|
|
18641
|
+
binding: 0,
|
|
18642
|
+
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
18643
|
+
buffer: { type: "read-only-storage" }
|
|
18644
|
+
},
|
|
18645
|
+
{
|
|
18646
|
+
binding: 1,
|
|
18647
|
+
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
18648
|
+
buffer: { type: "read-only-storage" }
|
|
18649
|
+
}
|
|
18650
|
+
]
|
|
18651
|
+
};
|
|
18652
|
+
// src/backends/webgpu/WebGPUTextShader.ts
|
|
18653
|
+
var deets = new _t2(text_wgsl_default);
|
|
18654
|
+
var struct = deets.structs.find((s3) => s3.name === "TextBlockDescriptor");
|
|
18655
|
+
if (!struct) {
|
|
18656
|
+
throw new Error("FormattedText struct not found");
|
|
18657
|
+
}
|
|
18658
|
+
var textDescriptorInstanceSize = struct.size;
|
|
18659
|
+
|
|
18660
|
+
class WebGPUTextShader {
|
|
18661
|
+
label = "text";
|
|
18662
|
+
code = text_wgsl_default;
|
|
18663
|
+
#backend;
|
|
18664
|
+
#pipeline;
|
|
18665
|
+
#bindGroups = [];
|
|
18666
|
+
#font;
|
|
18667
|
+
#maxCharCount;
|
|
18668
|
+
#engineUniformsBuffer;
|
|
18669
|
+
#descriptorBuffer;
|
|
18670
|
+
#textBlockBuffer;
|
|
18671
|
+
#cpuDescriptorBuffer;
|
|
18672
|
+
#cpuTextBlockBuffer;
|
|
18673
|
+
#instanceIndex = 0;
|
|
18674
|
+
#textBlockOffset = 0;
|
|
18675
|
+
constructor(backend, pipeline, font, _colorFormat, instanceCount) {
|
|
18676
|
+
this.#backend = backend;
|
|
18677
|
+
const device = backend.device;
|
|
18678
|
+
this.#font = font;
|
|
18679
|
+
this.#pipeline = pipeline.pipeline;
|
|
18680
|
+
this.#maxCharCount = pipeline.maxCharCount;
|
|
18681
|
+
this.#descriptorBuffer = device.createBuffer({
|
|
18682
|
+
label: "msdf text descriptor buffer",
|
|
18683
|
+
size: textDescriptorInstanceSize * instanceCount,
|
|
18684
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
|
|
18685
|
+
});
|
|
18686
|
+
this.#cpuDescriptorBuffer = new Float32Array(instanceCount * textDescriptorInstanceSize / Float32Array.BYTES_PER_ELEMENT);
|
|
18687
|
+
this.#cpuTextBlockBuffer = new Float32Array(instanceCount * this.maxCharCount * 4);
|
|
18688
|
+
this.#engineUniformsBuffer = device.createBuffer({
|
|
18689
|
+
label: "msdf view projection matrix",
|
|
18690
|
+
size: Float32Array.BYTES_PER_ELEMENT * 12,
|
|
18691
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
18692
|
+
});
|
|
18693
|
+
this.#textBlockBuffer = device.createBuffer({
|
|
18694
|
+
label: "msdf text buffer",
|
|
18695
|
+
size: instanceCount * this.maxCharCount * 4 * Float32Array.BYTES_PER_ELEMENT,
|
|
18696
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
|
|
18697
|
+
});
|
|
18698
|
+
this.#bindGroups.push(pipeline.fontBindGroup);
|
|
18699
|
+
this.#bindGroups.push(device.createBindGroup({
|
|
18700
|
+
label: "msdf text bind group",
|
|
18701
|
+
layout: pipeline.pipeline.getBindGroupLayout(1),
|
|
18702
|
+
entries: [
|
|
18703
|
+
{
|
|
18704
|
+
binding: 0,
|
|
18705
|
+
resource: { buffer: this.#descriptorBuffer }
|
|
18706
|
+
},
|
|
18707
|
+
{
|
|
18708
|
+
binding: 1,
|
|
18709
|
+
resource: { buffer: this.#textBlockBuffer }
|
|
18710
|
+
}
|
|
18711
|
+
]
|
|
18712
|
+
}));
|
|
18713
|
+
const engineUniformsBindGroup = device.createBindGroup({
|
|
18714
|
+
label: "msdf text uniforms bind group",
|
|
18715
|
+
layout: pipeline.pipeline.getBindGroupLayout(2),
|
|
18716
|
+
entries: [
|
|
18717
|
+
{
|
|
18718
|
+
binding: 0,
|
|
18719
|
+
resource: { buffer: this.#engineUniformsBuffer }
|
|
18720
|
+
}
|
|
18721
|
+
]
|
|
18722
|
+
});
|
|
18723
|
+
this.#bindGroups.push(engineUniformsBindGroup);
|
|
18724
|
+
}
|
|
18725
|
+
startFrame(uniform) {
|
|
18726
|
+
const device = this.#backend.device;
|
|
18727
|
+
device.queue.writeBuffer(this.#engineUniformsBuffer, 0, uniform.viewProjectionMatrix);
|
|
18728
|
+
this.#instanceIndex = 0;
|
|
18729
|
+
this.#textBlockOffset = 0;
|
|
18730
|
+
}
|
|
18731
|
+
processBatch(nodes) {
|
|
18732
|
+
if (nodes.length === 0)
|
|
18733
|
+
return 0;
|
|
18734
|
+
const renderPass = this.#backend.renderPass;
|
|
18735
|
+
renderPass.setPipeline(this.#pipeline);
|
|
18736
|
+
for (let i3 = 0;i3 < this.#bindGroups.length; i3++) {
|
|
18737
|
+
renderPass.setBindGroup(i3, this.#bindGroups[i3]);
|
|
18738
|
+
}
|
|
18739
|
+
for (const node of nodes) {
|
|
18740
|
+
if (!(node instanceof TextNode)) {
|
|
18741
|
+
console.error(node);
|
|
18742
|
+
throw new Error(`Tried to use WebGPUTextShader on something that isn't a TextNode: ${node}`);
|
|
18743
|
+
}
|
|
18744
|
+
const text = node.text;
|
|
18745
|
+
const formatting = node.formatting;
|
|
18746
|
+
const measurements = measureText(this.#font, text, formatting.wordWrap);
|
|
18747
|
+
const textBlockSize = 4 * text.length;
|
|
18748
|
+
const textDescriptorOffset = this.#instanceIndex * textDescriptorInstanceSize / Float32Array.BYTES_PER_ELEMENT;
|
|
18749
|
+
this.#cpuDescriptorBuffer.set(node.matrix, textDescriptorOffset);
|
|
18750
|
+
this.#cpuDescriptorBuffer.set([node.tint.r, node.tint.g, node.tint.b, node.tint.a], textDescriptorOffset + 12);
|
|
18751
|
+
const size = node.size ?? measurements;
|
|
18752
|
+
const fontSize = formatting.shrinkToFit ? findLargestFontSize(this.#font, text, size, formatting) : formatting.fontSize;
|
|
18753
|
+
const actualFontSize = fontSize || DEFAULT_FONT_SIZE;
|
|
18754
|
+
this.#cpuDescriptorBuffer[textDescriptorOffset + 16] = actualFontSize;
|
|
18755
|
+
this.#cpuDescriptorBuffer[textDescriptorOffset + 17] = formatting.align === "center" ? 0 : measurements.width;
|
|
18756
|
+
this.#cpuDescriptorBuffer[textDescriptorOffset + 18] = measurements.height;
|
|
18757
|
+
this.#cpuDescriptorBuffer[textDescriptorOffset + 19] = this.#textBlockOffset / 4;
|
|
18758
|
+
shapeText(this.#font, text, size, actualFontSize, formatting, this.#cpuTextBlockBuffer, this.#textBlockOffset);
|
|
18759
|
+
this.#backend.device.queue.writeBuffer(this.#descriptorBuffer, textDescriptorOffset * Float32Array.BYTES_PER_ELEMENT, this.#cpuDescriptorBuffer, textDescriptorOffset, textDescriptorInstanceSize / Float32Array.BYTES_PER_ELEMENT);
|
|
18760
|
+
this.#backend.device.queue.writeBuffer(this.#textBlockBuffer, this.#textBlockOffset * Float32Array.BYTES_PER_ELEMENT, this.#cpuTextBlockBuffer, this.#textBlockOffset, textBlockSize);
|
|
18761
|
+
this.#textBlockOffset += textBlockSize;
|
|
18762
|
+
renderPass.draw(4, measurements.printedCharCount, 4 * this.#instanceIndex, 0);
|
|
18763
|
+
this.#instanceIndex++;
|
|
18764
|
+
}
|
|
18765
|
+
return nodes.length;
|
|
18766
|
+
}
|
|
18767
|
+
endFrame() {}
|
|
18768
|
+
get font() {
|
|
18769
|
+
return this.#font;
|
|
18770
|
+
}
|
|
18771
|
+
get maxCharCount() {
|
|
18772
|
+
return this.#maxCharCount;
|
|
18773
|
+
}
|
|
18774
|
+
}
|
|
18775
|
+
|
|
18776
|
+
// src/scene/Batcher.ts
|
|
18777
|
+
class Batcher {
|
|
18778
|
+
nodes = [];
|
|
18779
|
+
layers = [];
|
|
18780
|
+
pipelines = [];
|
|
18781
|
+
enqueue(node) {
|
|
18782
|
+
if (node.renderComponent && node.isActive) {
|
|
18783
|
+
this.nodes.push(node);
|
|
18784
|
+
const z3 = node.layer;
|
|
18785
|
+
const layer = this.#findOrCreateLayer(z3);
|
|
18786
|
+
const pipeline = this.#findOrCreatePipeline(layer, node.renderComponent.shader);
|
|
18787
|
+
pipeline.nodes.push(node);
|
|
18788
|
+
}
|
|
18789
|
+
for (const kid of node.kids) {
|
|
18790
|
+
this.enqueue(kid);
|
|
18791
|
+
}
|
|
18792
|
+
}
|
|
18793
|
+
flush() {
|
|
18794
|
+
this.nodes = [];
|
|
18795
|
+
this.layers = [];
|
|
18796
|
+
this.pipelines = [];
|
|
18797
|
+
}
|
|
18798
|
+
#findOrCreateLayer(z3) {
|
|
18799
|
+
let layer = this.layers.find((l3) => l3.z === z3);
|
|
18800
|
+
if (!layer) {
|
|
18801
|
+
layer = { z: z3, pipelines: [] };
|
|
18802
|
+
this.layers.push(layer);
|
|
18803
|
+
this.layers.sort((a3, b3) => a3.z - b3.z);
|
|
18804
|
+
}
|
|
18805
|
+
return layer;
|
|
18806
|
+
}
|
|
18807
|
+
#findOrCreatePipeline(layer, shader) {
|
|
18808
|
+
let pipeline = layer.pipelines.find((p3) => p3.shader === shader);
|
|
18809
|
+
if (!pipeline) {
|
|
18810
|
+
pipeline = { shader, nodes: [] };
|
|
18811
|
+
layer.pipelines.push(pipeline);
|
|
18812
|
+
this.pipelines.push(pipeline);
|
|
18813
|
+
}
|
|
18814
|
+
return pipeline;
|
|
18815
|
+
}
|
|
18816
|
+
}
|
|
18817
|
+
|
|
18818
|
+
// src/scene/Camera.ts
|
|
18819
|
+
class Camera {
|
|
18820
|
+
#position = { x: 0, y: 0 };
|
|
18821
|
+
#zoom = 1;
|
|
18822
|
+
#rotation = 0;
|
|
18823
|
+
#isDirty = true;
|
|
18824
|
+
#matrix = mat3.create();
|
|
18825
|
+
get zoom() {
|
|
18826
|
+
return this.#zoom;
|
|
18827
|
+
}
|
|
18828
|
+
set zoom(value) {
|
|
18829
|
+
this.#zoom = value;
|
|
18830
|
+
this.setDirty();
|
|
18831
|
+
}
|
|
18832
|
+
get rotation() {
|
|
18833
|
+
return rad2deg(this.#rotation);
|
|
18834
|
+
}
|
|
18835
|
+
set rotation(value) {
|
|
18836
|
+
this.#rotation = deg2rad(value);
|
|
18837
|
+
this.setDirty();
|
|
18838
|
+
}
|
|
18839
|
+
get rotationRadians() {
|
|
18840
|
+
return this.#rotation;
|
|
18841
|
+
}
|
|
18842
|
+
set rotationRadians(value) {
|
|
18843
|
+
this.#rotation = value;
|
|
18844
|
+
this.setDirty();
|
|
18845
|
+
}
|
|
18846
|
+
get x() {
|
|
18847
|
+
return this.#position.x;
|
|
18848
|
+
}
|
|
18849
|
+
get y() {
|
|
18850
|
+
return this.#position.y;
|
|
18851
|
+
}
|
|
18852
|
+
set x(value) {
|
|
18853
|
+
this.#position.x = value;
|
|
18854
|
+
this.setDirty();
|
|
18855
|
+
}
|
|
18856
|
+
set y(value) {
|
|
18857
|
+
this.#position.y = value;
|
|
18858
|
+
this.setDirty();
|
|
18859
|
+
}
|
|
18860
|
+
get matrix() {
|
|
18861
|
+
if (this.#isDirty) {
|
|
18862
|
+
this.#isDirty = false;
|
|
18863
|
+
this.#matrix = createViewMatrix(this, this.#matrix);
|
|
18864
|
+
}
|
|
18865
|
+
return this.#matrix;
|
|
18866
|
+
}
|
|
18867
|
+
setDirty() {
|
|
18868
|
+
this.#isDirty = true;
|
|
18869
|
+
}
|
|
18870
|
+
}
|
|
18871
|
+
|
|
18872
|
+
// src/scene/QuadNode.ts
|
|
18873
|
+
var PRIMITIVE_TEXTURE = "__primitive__";
|
|
18874
|
+
var RESERVED_PRIMITIVE_INDEX_START = 1000;
|
|
18875
|
+
var CIRCLE_INDEX = 1001;
|
|
18876
|
+
var DEFAULT_REGION = {
|
|
18877
|
+
x: 0,
|
|
18878
|
+
y: 0,
|
|
18879
|
+
width: 0,
|
|
18880
|
+
height: 0
|
|
18881
|
+
};
|
|
18882
|
+
|
|
18883
|
+
class QuadNode extends SceneNode {
|
|
18884
|
+
assetManager;
|
|
18885
|
+
#color;
|
|
18886
|
+
#atlasCoords;
|
|
18887
|
+
#region;
|
|
18888
|
+
#matrixPool;
|
|
18889
|
+
#flip;
|
|
18890
|
+
#cropOffset;
|
|
18891
|
+
#cropRatio;
|
|
18892
|
+
#atlasSize;
|
|
18893
|
+
#textureId;
|
|
18894
|
+
#writeInstance;
|
|
18895
|
+
constructor(options, matrixPool) {
|
|
18896
|
+
assert(options.shader, "QuadNode requires a shader to be explicitly provided");
|
|
18897
|
+
assert(options.size, "QuadNode requires a size to be explicitly provided");
|
|
18898
|
+
assert(options.atlasCoords, "QuadNode requires atlas coords to be explicitly provided");
|
|
18899
|
+
options.render ??= {
|
|
18900
|
+
shader: options.shader,
|
|
18901
|
+
writeInstance: writeQuadInstance
|
|
18902
|
+
};
|
|
18903
|
+
super(options);
|
|
18904
|
+
assert(options.assetManager, "QuadNode requires an asset manager");
|
|
18905
|
+
this.assetManager = options.assetManager;
|
|
18906
|
+
if (options.atlasCoords && options.atlasCoords.atlasIndex >= RESERVED_PRIMITIVE_INDEX_START) {
|
|
18907
|
+
this.#textureId = PRIMITIVE_TEXTURE;
|
|
18908
|
+
this.#region = DEFAULT_REGION;
|
|
18909
|
+
this.#atlasSize = DEFAULT_REGION;
|
|
18910
|
+
} else {
|
|
18911
|
+
assert(options.textureId, "QuadNode requires texture id to be explicitly provided");
|
|
18912
|
+
this.#textureId = options.textureId;
|
|
18913
|
+
assert(options.region, "QuadNode requires a region to be explicitly provided");
|
|
18914
|
+
this.#region = options.region;
|
|
18915
|
+
assert(options.atlasSize, "QuadNode requires atlas size to be explicitly provided");
|
|
18916
|
+
this.#atlasSize = options.atlasSize;
|
|
18917
|
+
}
|
|
18918
|
+
this.#atlasCoords = options.atlasCoords;
|
|
18919
|
+
this.#color = options.color ?? { r: 1, g: 1, b: 1, a: 1 };
|
|
18920
|
+
this.#matrixPool = matrixPool;
|
|
18921
|
+
this.#flip = { x: options.flipX ? -1 : 1, y: options.flipY ? -1 : 1 };
|
|
18922
|
+
this.#cropOffset = options.cropOffset ?? { x: 0, y: 0 };
|
|
18923
|
+
this.#cropRatio = !this.#atlasCoords.uvScaleCropped ? { width: 1, height: 1 } : {
|
|
18924
|
+
width: this.#atlasCoords.uvScaleCropped.width / this.#atlasCoords.uvScale.width,
|
|
18925
|
+
height: this.#atlasCoords.uvScaleCropped.height / this.#atlasCoords.uvScale.height
|
|
18926
|
+
};
|
|
18927
|
+
this.#writeInstance = options.writeInstance;
|
|
18928
|
+
}
|
|
18929
|
+
get color() {
|
|
18930
|
+
return this.#color;
|
|
18931
|
+
}
|
|
18932
|
+
set color(value) {
|
|
18933
|
+
this.#color = value;
|
|
18934
|
+
}
|
|
18935
|
+
get size() {
|
|
18936
|
+
const size = super.size;
|
|
18937
|
+
if (!size) {
|
|
18938
|
+
throw new Error("QuadNode requires a size");
|
|
18939
|
+
}
|
|
18940
|
+
return size;
|
|
18941
|
+
}
|
|
18942
|
+
set size(val) {
|
|
18943
|
+
super.size = val;
|
|
18944
|
+
}
|
|
18945
|
+
get matrixWithSize() {
|
|
18946
|
+
const matrix = mat3.clone(this.matrix, this.#matrixPool.get());
|
|
18947
|
+
mat3.scale(matrix, [this.size.width * this.#flip.x, this.size.height * this.#flip.y], matrix);
|
|
18948
|
+
return matrix;
|
|
18949
|
+
}
|
|
18950
|
+
get atlasCoords() {
|
|
18951
|
+
return this.#atlasCoords;
|
|
18952
|
+
}
|
|
18953
|
+
get region() {
|
|
18954
|
+
return this.#region;
|
|
18955
|
+
}
|
|
18956
|
+
get writeInstance() {
|
|
18957
|
+
return this.#writeInstance;
|
|
18958
|
+
}
|
|
18959
|
+
get flipX() {
|
|
18960
|
+
return this.#flip.x === -1;
|
|
18961
|
+
}
|
|
18962
|
+
set flipX(value) {
|
|
18963
|
+
this.#flip.x = value ? -1 : 1;
|
|
18964
|
+
this.setDirty();
|
|
18965
|
+
}
|
|
18966
|
+
get flipY() {
|
|
18967
|
+
return this.#flip.y === -1;
|
|
18968
|
+
}
|
|
18969
|
+
set flipY(value) {
|
|
18970
|
+
this.#flip.y = value ? -1 : 1;
|
|
18971
|
+
this.setDirty();
|
|
18972
|
+
}
|
|
18973
|
+
get cropOffset() {
|
|
18974
|
+
return this.#cropOffset;
|
|
18975
|
+
}
|
|
18976
|
+
set cropOffset(value) {
|
|
18977
|
+
this.#cropOffset = value;
|
|
18978
|
+
}
|
|
18979
|
+
get textureId() {
|
|
18980
|
+
return this.#textureId;
|
|
18981
|
+
}
|
|
18982
|
+
get isPrimitive() {
|
|
18983
|
+
return this.#textureId === PRIMITIVE_TEXTURE;
|
|
18984
|
+
}
|
|
18985
|
+
get isCircle() {
|
|
18986
|
+
return this.#atlasCoords.atlasIndex === CIRCLE_INDEX;
|
|
18987
|
+
}
|
|
18988
|
+
extra = {
|
|
18989
|
+
setAtlasCoords: (value) => {
|
|
18990
|
+
this.#atlasCoords = value;
|
|
18991
|
+
},
|
|
18992
|
+
cropRatio: () => {
|
|
18993
|
+
return this.#cropRatio;
|
|
18994
|
+
},
|
|
18995
|
+
atlasSize: () => {
|
|
18996
|
+
return this.#atlasSize;
|
|
18997
|
+
}
|
|
18998
|
+
};
|
|
18999
|
+
}
|
|
19000
|
+
function writeQuadInstance(node, array, offset) {
|
|
19001
|
+
if (!(node instanceof QuadNode)) {
|
|
19002
|
+
throw new Error("QuadNode.writeInstance can only be called on QuadNodes");
|
|
19003
|
+
}
|
|
19004
|
+
array.set(node.matrixWithSize, offset);
|
|
19005
|
+
array.set([node.color.r, node.color.g, node.color.b, node.color.a], offset + 12);
|
|
19006
|
+
const region = node.region;
|
|
19007
|
+
if (node.textureId === PRIMITIVE_TEXTURE) {
|
|
19008
|
+
array.set([
|
|
19009
|
+
node.atlasCoords.uvOffset.x,
|
|
19010
|
+
node.atlasCoords.uvOffset.y,
|
|
19011
|
+
node.atlasCoords.uvScale.width,
|
|
19012
|
+
node.atlasCoords.uvScale.height
|
|
19013
|
+
], offset + 16);
|
|
19014
|
+
} else {
|
|
19015
|
+
const atlasSize = node.extra.atlasSize();
|
|
19016
|
+
array.set([
|
|
19017
|
+
node.atlasCoords.uvOffset.x + region.x / atlasSize.width,
|
|
19018
|
+
node.atlasCoords.uvOffset.y + region.y / atlasSize.height,
|
|
19019
|
+
region.width / atlasSize.width,
|
|
19020
|
+
region.height / atlasSize.height
|
|
19021
|
+
], offset + 16);
|
|
19022
|
+
}
|
|
19023
|
+
array.set([
|
|
19024
|
+
node.cropOffset.x / 2 / (node.atlasCoords.originalSize.width || 1),
|
|
19025
|
+
node.cropOffset.y / 2 / (node.atlasCoords.originalSize.height || 1),
|
|
19026
|
+
node.extra.cropRatio().width,
|
|
19027
|
+
node.extra.cropRatio().height
|
|
19028
|
+
], offset + 20);
|
|
19029
|
+
new DataView(array.buffer).setUint32(array.byteOffset + (offset + 24) * Float32Array.BYTES_PER_ELEMENT, node.atlasCoords.atlasIndex, true);
|
|
19030
|
+
node.writeInstance?.(array, offset + 28);
|
|
19031
|
+
return 1;
|
|
19032
|
+
}
|
|
19033
|
+
|
|
19034
|
+
// src/scene/JumboQuadNode.ts
|
|
19035
|
+
var MAT3_SIZE = 12;
|
|
19036
|
+
var VEC4F_SIZE = 4;
|
|
19037
|
+
|
|
19038
|
+
class JumboQuadNode extends QuadNode {
|
|
19039
|
+
#tiles;
|
|
19040
|
+
#matrixPool;
|
|
19041
|
+
constructor(options, matrixPool) {
|
|
19042
|
+
assert(options.shader, "JumboQuadNode requires a shader to be explicitly provided");
|
|
19043
|
+
assert(options.tiles && options.tiles.length > 0, "JumboQuadNode requires at least one tile to be provided");
|
|
19044
|
+
options.render ??= {
|
|
19045
|
+
shader: options.shader,
|
|
19046
|
+
writeInstance: writeJumboQuadInstance
|
|
19047
|
+
};
|
|
19048
|
+
super({
|
|
19049
|
+
...options,
|
|
19050
|
+
atlasCoords: options.tiles[0].atlasCoords
|
|
19051
|
+
}, matrixPool);
|
|
19052
|
+
this.#matrixPool = matrixPool;
|
|
19053
|
+
this.#tiles = [];
|
|
19054
|
+
for (const tile of options.tiles) {
|
|
19055
|
+
assert(tile.atlasCoords, "JumboQuadNode requires atlas coords to be provided");
|
|
19056
|
+
assert(tile.size, "JumboQuadNode requires a size to be provided");
|
|
19057
|
+
this.#tiles.push({
|
|
19058
|
+
textureId: tile.textureId,
|
|
19059
|
+
offset: tile.offset,
|
|
19060
|
+
size: tile.size,
|
|
19061
|
+
atlasCoords: tile.atlasCoords
|
|
19062
|
+
});
|
|
19063
|
+
}
|
|
19064
|
+
}
|
|
19065
|
+
get atlasCoords() {
|
|
19066
|
+
throw new Error("JumboQuadNode does not have a single atlas coords");
|
|
19067
|
+
}
|
|
19068
|
+
get tiles() {
|
|
19069
|
+
return this.#tiles;
|
|
19070
|
+
}
|
|
19071
|
+
getTileMatrix(tile) {
|
|
19072
|
+
const matrix = mat3.clone(this.matrix, this.#matrixPool.get());
|
|
19073
|
+
const originalSize = {
|
|
19074
|
+
width: Math.max(...this.#tiles.map((t3) => t3.offset.x + t3.size.width)),
|
|
19075
|
+
height: Math.max(...this.#tiles.map((t3) => t3.offset.y + t3.size.height))
|
|
19076
|
+
};
|
|
19077
|
+
const proportionalSize = {
|
|
19078
|
+
width: this.size.width / originalSize.width,
|
|
19079
|
+
height: this.size.height / originalSize.height
|
|
19080
|
+
};
|
|
19081
|
+
const centerOffset = {
|
|
19082
|
+
x: tile.offset.x + tile.size.width / 2 - originalSize.width / 2,
|
|
19083
|
+
y: -(tile.offset.y + tile.size.height / 2 - originalSize.height / 2)
|
|
19084
|
+
};
|
|
19085
|
+
mat3.translate(matrix, [
|
|
19086
|
+
centerOffset.x * proportionalSize.width,
|
|
19087
|
+
centerOffset.y * proportionalSize.height
|
|
19088
|
+
], matrix);
|
|
19089
|
+
mat3.scale(matrix, [
|
|
19090
|
+
tile.size.width * proportionalSize.width * (this.flipX ? -1 : 1),
|
|
19091
|
+
tile.size.height * proportionalSize.height * (this.flipY ? -1 : 1)
|
|
19092
|
+
], matrix);
|
|
19093
|
+
return matrix;
|
|
19094
|
+
}
|
|
19095
|
+
}
|
|
19096
|
+
function writeJumboQuadInstance(node, array, offset) {
|
|
19097
|
+
if (!(node instanceof JumboQuadNode)) {
|
|
19098
|
+
throw new Error("JumboQuadNode.writeJumboQuadInstance can only be called on JumboQuadNodes");
|
|
19099
|
+
}
|
|
19100
|
+
let tileOffset = 0;
|
|
19101
|
+
for (const tile of node.tiles) {
|
|
19102
|
+
const coord = tile.atlasCoords;
|
|
19103
|
+
const matrix = node.getTileMatrix(tile);
|
|
19104
|
+
array.set(matrix, offset + tileOffset);
|
|
19105
|
+
tileOffset += MAT3_SIZE;
|
|
19106
|
+
array.set([node.color.r, node.color.g, node.color.b, node.color.a], offset + tileOffset);
|
|
19107
|
+
tileOffset += VEC4F_SIZE;
|
|
19108
|
+
array.set([
|
|
19109
|
+
coord.uvOffset.x,
|
|
19110
|
+
coord.uvOffset.y,
|
|
19111
|
+
coord.uvScale.width,
|
|
19112
|
+
coord.uvScale.height
|
|
19113
|
+
], offset + tileOffset);
|
|
19114
|
+
tileOffset += VEC4F_SIZE;
|
|
19115
|
+
const cropRatio = !coord.uvScaleCropped ? { width: 1, height: 1 } : {
|
|
19116
|
+
width: coord.uvScaleCropped.width / coord.uvScale.width,
|
|
19117
|
+
height: coord.uvScaleCropped.height / coord.uvScale.height
|
|
19118
|
+
};
|
|
19119
|
+
array.set([
|
|
19120
|
+
tile.atlasCoords.cropOffset.x / 2 / (tile.atlasCoords.originalSize.width || 1),
|
|
19121
|
+
tile.atlasCoords.cropOffset.y / 2 / (tile.atlasCoords.originalSize.height || 1),
|
|
19122
|
+
cropRatio.width,
|
|
19123
|
+
cropRatio.height
|
|
19124
|
+
], offset + tileOffset);
|
|
19125
|
+
tileOffset += VEC4F_SIZE;
|
|
19126
|
+
new DataView(array.buffer).setUint32(array.byteOffset + (offset + tileOffset) * Float32Array.BYTES_PER_ELEMENT, coord.atlasIndex, true);
|
|
19127
|
+
tileOffset += VEC4F_SIZE;
|
|
19128
|
+
}
|
|
19129
|
+
node.writeInstance?.(array, offset + tileOffset);
|
|
19130
|
+
return node.tiles.length;
|
|
18861
19131
|
}
|
|
18862
|
-
var fontBindGroupLayout = {
|
|
18863
|
-
label: "MSDF font group layout",
|
|
18864
|
-
entries: [
|
|
18865
|
-
{
|
|
18866
|
-
binding: 0,
|
|
18867
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
18868
|
-
texture: {}
|
|
18869
|
-
},
|
|
18870
|
-
{
|
|
18871
|
-
binding: 1,
|
|
18872
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
18873
|
-
sampler: {}
|
|
18874
|
-
},
|
|
18875
|
-
{
|
|
18876
|
-
binding: 2,
|
|
18877
|
-
visibility: GPUShaderStage.VERTEX,
|
|
18878
|
-
buffer: { type: "read-only-storage" }
|
|
18879
|
-
},
|
|
18880
|
-
{
|
|
18881
|
-
binding: 3,
|
|
18882
|
-
visibility: GPUShaderStage.VERTEX,
|
|
18883
|
-
buffer: {}
|
|
18884
|
-
}
|
|
18885
|
-
]
|
|
18886
|
-
};
|
|
18887
|
-
var engineUniformBindGroupLayout = {
|
|
18888
|
-
label: "Uniform bind group",
|
|
18889
|
-
entries: [
|
|
18890
|
-
{
|
|
18891
|
-
binding: 0,
|
|
18892
|
-
visibility: GPUShaderStage.VERTEX,
|
|
18893
|
-
buffer: {}
|
|
18894
|
-
}
|
|
18895
|
-
]
|
|
18896
|
-
};
|
|
18897
|
-
var sampler = {
|
|
18898
|
-
label: "MSDF text sampler",
|
|
18899
|
-
minFilter: "linear",
|
|
18900
|
-
magFilter: "linear",
|
|
18901
|
-
mipmapFilter: "linear",
|
|
18902
|
-
maxAnisotropy: 16
|
|
18903
|
-
};
|
|
18904
|
-
var textUniformBindGroupLayout = {
|
|
18905
|
-
label: "MSDF text block uniform",
|
|
18906
|
-
entries: [
|
|
18907
|
-
{
|
|
18908
|
-
binding: 0,
|
|
18909
|
-
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
18910
|
-
buffer: { type: "read-only-storage" }
|
|
18911
|
-
},
|
|
18912
|
-
{
|
|
18913
|
-
binding: 1,
|
|
18914
|
-
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
18915
|
-
buffer: { type: "read-only-storage" }
|
|
18916
|
-
}
|
|
18917
|
-
]
|
|
18918
|
-
};
|
|
18919
19132
|
|
|
18920
19133
|
// src/backends/webgpu/wgsl/pixel-scraping.wgsl.ts
|
|
18921
19134
|
var pixel_scraping_wgsl_default = `
|
|
@@ -19290,130 +19503,6 @@ function createPipelines(device, label) {
|
|
|
19290
19503
|
};
|
|
19291
19504
|
}
|
|
19292
19505
|
|
|
19293
|
-
// src/backends/webgpu/WebGPUTextShader.ts
|
|
19294
|
-
var deets = new _t2(text_wgsl_default);
|
|
19295
|
-
var struct = deets.structs.find((s3) => s3.name === "TextBlockDescriptor");
|
|
19296
|
-
if (!struct) {
|
|
19297
|
-
throw new Error("FormattedText struct not found");
|
|
19298
|
-
}
|
|
19299
|
-
var textDescriptorInstanceSize = struct.size;
|
|
19300
|
-
|
|
19301
|
-
class WebGPUTextShader2 {
|
|
19302
|
-
label = "text";
|
|
19303
|
-
code = text_wgsl_default;
|
|
19304
|
-
#backend;
|
|
19305
|
-
#pipeline;
|
|
19306
|
-
#bindGroups = [];
|
|
19307
|
-
#font;
|
|
19308
|
-
#maxCharCount;
|
|
19309
|
-
#engineUniformsBuffer;
|
|
19310
|
-
#descriptorBuffer;
|
|
19311
|
-
#textBlockBuffer;
|
|
19312
|
-
#cpuDescriptorBuffer;
|
|
19313
|
-
#cpuTextBlockBuffer;
|
|
19314
|
-
#instanceIndex = 0;
|
|
19315
|
-
#textBlockOffset = 0;
|
|
19316
|
-
constructor(backend, pipeline, font, _colorFormat, instanceCount) {
|
|
19317
|
-
this.#backend = backend;
|
|
19318
|
-
const device = backend.device;
|
|
19319
|
-
this.#font = font;
|
|
19320
|
-
this.#pipeline = pipeline.pipeline;
|
|
19321
|
-
this.#maxCharCount = pipeline.maxCharCount;
|
|
19322
|
-
this.#descriptorBuffer = device.createBuffer({
|
|
19323
|
-
label: "msdf text descriptor buffer",
|
|
19324
|
-
size: textDescriptorInstanceSize * instanceCount,
|
|
19325
|
-
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
|
|
19326
|
-
});
|
|
19327
|
-
this.#cpuDescriptorBuffer = new Float32Array(instanceCount * textDescriptorInstanceSize / Float32Array.BYTES_PER_ELEMENT);
|
|
19328
|
-
this.#cpuTextBlockBuffer = new Float32Array(instanceCount * this.maxCharCount * 4);
|
|
19329
|
-
this.#engineUniformsBuffer = device.createBuffer({
|
|
19330
|
-
label: "msdf view projection matrix",
|
|
19331
|
-
size: Float32Array.BYTES_PER_ELEMENT * 12,
|
|
19332
|
-
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
19333
|
-
});
|
|
19334
|
-
this.#textBlockBuffer = device.createBuffer({
|
|
19335
|
-
label: "msdf text buffer",
|
|
19336
|
-
size: instanceCount * this.maxCharCount * 4 * Float32Array.BYTES_PER_ELEMENT,
|
|
19337
|
-
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
|
|
19338
|
-
});
|
|
19339
|
-
this.#bindGroups.push(pipeline.fontBindGroup);
|
|
19340
|
-
this.#bindGroups.push(device.createBindGroup({
|
|
19341
|
-
label: "msdf text bind group",
|
|
19342
|
-
layout: pipeline.pipeline.getBindGroupLayout(1),
|
|
19343
|
-
entries: [
|
|
19344
|
-
{
|
|
19345
|
-
binding: 0,
|
|
19346
|
-
resource: { buffer: this.#descriptorBuffer }
|
|
19347
|
-
},
|
|
19348
|
-
{
|
|
19349
|
-
binding: 1,
|
|
19350
|
-
resource: { buffer: this.#textBlockBuffer }
|
|
19351
|
-
}
|
|
19352
|
-
]
|
|
19353
|
-
}));
|
|
19354
|
-
const engineUniformsBindGroup = device.createBindGroup({
|
|
19355
|
-
label: "msdf text uniforms bind group",
|
|
19356
|
-
layout: pipeline.pipeline.getBindGroupLayout(2),
|
|
19357
|
-
entries: [
|
|
19358
|
-
{
|
|
19359
|
-
binding: 0,
|
|
19360
|
-
resource: { buffer: this.#engineUniformsBuffer }
|
|
19361
|
-
}
|
|
19362
|
-
]
|
|
19363
|
-
});
|
|
19364
|
-
this.#bindGroups.push(engineUniformsBindGroup);
|
|
19365
|
-
}
|
|
19366
|
-
startFrame(uniform) {
|
|
19367
|
-
const device = this.#backend.device;
|
|
19368
|
-
device.queue.writeBuffer(this.#engineUniformsBuffer, 0, uniform.viewProjectionMatrix);
|
|
19369
|
-
this.#instanceIndex = 0;
|
|
19370
|
-
this.#textBlockOffset = 0;
|
|
19371
|
-
}
|
|
19372
|
-
processBatch(nodes) {
|
|
19373
|
-
if (nodes.length === 0)
|
|
19374
|
-
return 0;
|
|
19375
|
-
const renderPass = this.#backend.renderPass;
|
|
19376
|
-
renderPass.setPipeline(this.#pipeline);
|
|
19377
|
-
for (let i3 = 0;i3 < this.#bindGroups.length; i3++) {
|
|
19378
|
-
renderPass.setBindGroup(i3, this.#bindGroups[i3]);
|
|
19379
|
-
}
|
|
19380
|
-
for (const node of nodes) {
|
|
19381
|
-
if (!(node instanceof TextNode)) {
|
|
19382
|
-
console.error(node);
|
|
19383
|
-
throw new Error(`Tried to use WebGPUTextShader on something that isn't a TextNode: ${node}`);
|
|
19384
|
-
}
|
|
19385
|
-
const text = node.text;
|
|
19386
|
-
const formatting = node.formatting;
|
|
19387
|
-
const measurements = measureText(this.#font, text, formatting.wordWrap);
|
|
19388
|
-
const textBlockSize = 4 * text.length;
|
|
19389
|
-
const textDescriptorOffset = this.#instanceIndex * textDescriptorInstanceSize / Float32Array.BYTES_PER_ELEMENT;
|
|
19390
|
-
this.#cpuDescriptorBuffer.set(node.matrix, textDescriptorOffset);
|
|
19391
|
-
this.#cpuDescriptorBuffer.set([node.tint.r, node.tint.g, node.tint.b, node.tint.a], textDescriptorOffset + 12);
|
|
19392
|
-
const size = node.size ?? measurements;
|
|
19393
|
-
const fontSize = formatting.shrinkToFit ? findLargestFontSize(this.#font, text, size, formatting) : formatting.fontSize;
|
|
19394
|
-
const actualFontSize = fontSize || DEFAULT_FONT_SIZE;
|
|
19395
|
-
this.#cpuDescriptorBuffer[textDescriptorOffset + 16] = actualFontSize;
|
|
19396
|
-
this.#cpuDescriptorBuffer[textDescriptorOffset + 17] = formatting.align === "center" ? 0 : measurements.width;
|
|
19397
|
-
this.#cpuDescriptorBuffer[textDescriptorOffset + 18] = measurements.height;
|
|
19398
|
-
this.#cpuDescriptorBuffer[textDescriptorOffset + 19] = this.#textBlockOffset / 4;
|
|
19399
|
-
shapeText(this.#font, text, size, actualFontSize, formatting, this.#cpuTextBlockBuffer, this.#textBlockOffset);
|
|
19400
|
-
this.#backend.device.queue.writeBuffer(this.#descriptorBuffer, textDescriptorOffset * Float32Array.BYTES_PER_ELEMENT, this.#cpuDescriptorBuffer, textDescriptorOffset, textDescriptorInstanceSize / Float32Array.BYTES_PER_ELEMENT);
|
|
19401
|
-
this.#backend.device.queue.writeBuffer(this.#textBlockBuffer, this.#textBlockOffset * Float32Array.BYTES_PER_ELEMENT, this.#cpuTextBlockBuffer, this.#textBlockOffset, textBlockSize);
|
|
19402
|
-
this.#textBlockOffset += textBlockSize;
|
|
19403
|
-
renderPass.draw(4, measurements.printedCharCount, 4 * this.#instanceIndex, 0);
|
|
19404
|
-
this.#instanceIndex++;
|
|
19405
|
-
}
|
|
19406
|
-
return nodes.length;
|
|
19407
|
-
}
|
|
19408
|
-
endFrame() {}
|
|
19409
|
-
get font() {
|
|
19410
|
-
return this.#font;
|
|
19411
|
-
}
|
|
19412
|
-
get maxCharCount() {
|
|
19413
|
-
return this.#maxCharCount;
|
|
19414
|
-
}
|
|
19415
|
-
}
|
|
19416
|
-
|
|
19417
19506
|
// src/textures/Bundles.ts
|
|
19418
19507
|
class Bundles {
|
|
19419
19508
|
#bundles = new Map;
|
|
@@ -20088,13 +20177,13 @@ class AssetManager {
|
|
|
20088
20177
|
const webgpuBackend = this.#backend;
|
|
20089
20178
|
const device = webgpuBackend.device;
|
|
20090
20179
|
const presentationFormat = webgpuBackend.presentationFormat;
|
|
20091
|
-
const fontPipeline = await
|
|
20092
|
-
const textShader = new
|
|
20180
|
+
const fontPipeline = await FontPipeline.create(device, font, presentationFormat, limits.maxTextLength);
|
|
20181
|
+
const textShader = new WebGPUTextShader(webgpuBackend, fontPipeline, font, presentationFormat, limits.instanceCount);
|
|
20093
20182
|
this.#fonts.set(id, textShader);
|
|
20094
20183
|
} else {
|
|
20095
20184
|
const webglBackend = this.#backend;
|
|
20096
|
-
const fontPipeline =
|
|
20097
|
-
const textShader = new
|
|
20185
|
+
const fontPipeline = WebGLFontPipeline.create(webglBackend.gl, font, limits.maxTextLength);
|
|
20186
|
+
const textShader = new WebGLTextShader(webglBackend, fontPipeline);
|
|
20098
20187
|
this.#fonts.set(id, textShader);
|
|
20099
20188
|
}
|
|
20100
20189
|
return id;
|
|
@@ -20237,6 +20326,13 @@ class AssetManager {
|
|
|
20237
20326
|
}
|
|
20238
20327
|
}
|
|
20239
20328
|
|
|
20329
|
+
// src/utils/mod.ts
|
|
20330
|
+
var exports_mod2 = {};
|
|
20331
|
+
__export(exports_mod2, {
|
|
20332
|
+
assert: () => assert,
|
|
20333
|
+
Pool: () => Pool
|
|
20334
|
+
});
|
|
20335
|
+
|
|
20240
20336
|
// src/utils/pool.ts
|
|
20241
20337
|
class Pool {
|
|
20242
20338
|
#items = [];
|
|
@@ -20258,7 +20354,6 @@ class Pool {
|
|
|
20258
20354
|
this.#index = 0;
|
|
20259
20355
|
}
|
|
20260
20356
|
}
|
|
20261
|
-
|
|
20262
20357
|
// src/Toodle.ts
|
|
20263
20358
|
class Toodle {
|
|
20264
20359
|
assets;
|
|
@@ -20595,11 +20690,11 @@ class Toodle {
|
|
|
20595
20690
|
}
|
|
20596
20691
|
let backend;
|
|
20597
20692
|
if (backendType === "webgpu") {
|
|
20598
|
-
backend = await
|
|
20693
|
+
backend = await WebGPUBackend.create(canvas, {
|
|
20599
20694
|
limits: options?.limits
|
|
20600
20695
|
});
|
|
20601
20696
|
} else {
|
|
20602
|
-
backend = await
|
|
20697
|
+
backend = await WebGLBackend.create(canvas, {
|
|
20603
20698
|
limits: options?.limits
|
|
20604
20699
|
});
|
|
20605
20700
|
}
|
|
@@ -20617,20 +20712,204 @@ class Toodle {
|
|
|
20617
20712
|
return this.#backend;
|
|
20618
20713
|
}
|
|
20619
20714
|
}
|
|
20715
|
+
// src/colors/mod.ts
|
|
20716
|
+
var exports_mod3 = {};
|
|
20717
|
+
__export(exports_mod3, {
|
|
20718
|
+
web: () => web
|
|
20719
|
+
});
|
|
20720
|
+
var web = Object.freeze({
|
|
20721
|
+
aliceBlue: { r: 0.941176, g: 0.972549, b: 1, a: 1 },
|
|
20722
|
+
antiqueWhite: { r: 0.980392, g: 0.921569, b: 0.843137, a: 1 },
|
|
20723
|
+
aqua: { r: 0, g: 1, b: 1, a: 1 },
|
|
20724
|
+
aquamarine: { r: 0.498039, g: 1, b: 0.831373, a: 1 },
|
|
20725
|
+
azure: { r: 0.941176, g: 1, b: 1, a: 1 },
|
|
20726
|
+
beige: { r: 0.960784, g: 0.960784, b: 0.862745, a: 1 },
|
|
20727
|
+
bisque: { r: 1, g: 0.894118, b: 0.768627, a: 1 },
|
|
20728
|
+
black: { r: 0, g: 0, b: 0, a: 1 },
|
|
20729
|
+
blanchedAlmond: { r: 1, g: 0.921569, b: 0.803922, a: 1 },
|
|
20730
|
+
blue: { r: 0, g: 0, b: 1, a: 1 },
|
|
20731
|
+
blueViolet: { r: 0.541176, g: 0.168627, b: 0.886275, a: 1 },
|
|
20732
|
+
brown: { r: 0.647059, g: 0.164706, b: 0.164706, a: 1 },
|
|
20733
|
+
burlywood: { r: 0.870588, g: 0.721569, b: 0.529412, a: 1 },
|
|
20734
|
+
cadetBlue: { r: 0.372549, g: 0.619608, b: 0.627451, a: 1 },
|
|
20735
|
+
chartreuse: { r: 0.498039, g: 1, b: 0, a: 1 },
|
|
20736
|
+
chocolate: { r: 0.823529, g: 0.411765, b: 0.117647, a: 1 },
|
|
20737
|
+
coral: { r: 1, g: 0.498039, b: 0.313726, a: 1 },
|
|
20738
|
+
cornflowerBlue: { r: 0.392157, g: 0.584314, b: 0.929412, a: 1 },
|
|
20739
|
+
cornsilk: { r: 1, g: 0.972549, b: 0.862745, a: 1 },
|
|
20740
|
+
crimson: { r: 0.862745, g: 0.0784314, b: 0.235294, a: 1 },
|
|
20741
|
+
cyan: { r: 0, g: 1, b: 1, a: 1 },
|
|
20742
|
+
darkBlue: { r: 0, g: 0, b: 0.545098, a: 1 },
|
|
20743
|
+
darkCyan: { r: 0, g: 0.545098, b: 0.545098, a: 1 },
|
|
20744
|
+
darkGoldenrod: { r: 0.721569, g: 0.52549, b: 0.0431373, a: 1 },
|
|
20745
|
+
darkGray: { r: 0.662745, g: 0.662745, b: 0.662745, a: 1 },
|
|
20746
|
+
darkGreen: { r: 0, g: 0.392157, b: 0, a: 1 },
|
|
20747
|
+
darkKhaki: { r: 0.741176, g: 0.717647, b: 0.419608, a: 1 },
|
|
20748
|
+
darkMagenta: { r: 0.545098, g: 0, b: 0.545098, a: 1 },
|
|
20749
|
+
darkOliveGreen: { r: 0.333333, g: 0.419608, b: 0.184314, a: 1 },
|
|
20750
|
+
darkOrange: { r: 1, g: 0.54902, b: 0, a: 1 },
|
|
20751
|
+
darkOrchid: { r: 0.6, g: 0.196078, b: 0.8, a: 1 },
|
|
20752
|
+
darkRed: { r: 0.545098, g: 0, b: 0, a: 1 },
|
|
20753
|
+
darkSalmon: { r: 0.913725, g: 0.588235, b: 0.478431, a: 1 },
|
|
20754
|
+
darkSeaGreen: { r: 0.560784, g: 0.737255, b: 0.560784, a: 1 },
|
|
20755
|
+
darkSlateBlue: { r: 0.282353, g: 0.239216, b: 0.545098, a: 1 },
|
|
20756
|
+
darkSlateGray: { r: 0.184314, g: 0.309804, b: 0.309804, a: 1 },
|
|
20757
|
+
darkTurquoise: { r: 0, g: 0.807843, b: 0.819608, a: 1 },
|
|
20758
|
+
darkViolet: { r: 0.580392, g: 0, b: 0.827451, a: 1 },
|
|
20759
|
+
deepPink: { r: 1, g: 0.0784314, b: 0.576471, a: 1 },
|
|
20760
|
+
deepSkyBlue: { r: 0, g: 0.74902, b: 1, a: 1 },
|
|
20761
|
+
dimGray: { r: 0.411765, g: 0.411765, b: 0.411765, a: 1 },
|
|
20762
|
+
dodgerBlue: { r: 0.117647, g: 0.564706, b: 1, a: 1 },
|
|
20763
|
+
firebrick: { r: 0.698039, g: 0.133333, b: 0.133333, a: 1 },
|
|
20764
|
+
floralWhite: { r: 1, g: 0.980392, b: 0.941176, a: 1 },
|
|
20765
|
+
forestGreen: { r: 0.133333, g: 0.545098, b: 0.133333, a: 1 },
|
|
20766
|
+
fuchsia: { r: 1, g: 0, b: 1, a: 1 },
|
|
20767
|
+
gainsboro: { r: 0.862745, g: 0.862745, b: 0.862745, a: 1 },
|
|
20768
|
+
ghostWhite: { r: 0.972549, g: 0.972549, b: 1, a: 1 },
|
|
20769
|
+
gold: { r: 1, g: 0.843137, b: 0, a: 1 },
|
|
20770
|
+
goldenrod: { r: 0.854902, g: 0.647059, b: 0.12549, a: 1 },
|
|
20771
|
+
gray: { r: 0.745098, g: 0.745098, b: 0.745098, a: 1 },
|
|
20772
|
+
green: { r: 0, g: 1, b: 0, a: 1 },
|
|
20773
|
+
greenYellow: { r: 0.678431, g: 1, b: 0.184314, a: 1 },
|
|
20774
|
+
honeydew: { r: 0.941176, g: 1, b: 0.941176, a: 1 },
|
|
20775
|
+
hotPink: { r: 1, g: 0.411765, b: 0.705882, a: 1 },
|
|
20776
|
+
indigo: { r: 0.294118, g: 0, b: 0.509804, a: 1 },
|
|
20777
|
+
ivory: { r: 1, g: 1, b: 0.941176, a: 1 },
|
|
20778
|
+
khaki: { r: 0.941176, g: 0.901961, b: 0.54902, a: 1 },
|
|
20779
|
+
lavender: { r: 0.901961, g: 0.901961, b: 0.980392, a: 1 },
|
|
20780
|
+
lavenderBlush: { r: 1, g: 0.941176, b: 0.960784, a: 1 },
|
|
20781
|
+
lawnGreen: { r: 0.486275, g: 0.988235, b: 0, a: 1 },
|
|
20782
|
+
lemonChiffon: { r: 1, g: 0.980392, b: 0.803922, a: 1 },
|
|
20783
|
+
lightBlue: { r: 0.678431, g: 0.847059, b: 0.901961, a: 1 },
|
|
20784
|
+
lightCoral: { r: 0.941176, g: 0.501961, b: 0.501961, a: 1 },
|
|
20785
|
+
lightCyan: { r: 0.878431, g: 1, b: 1, a: 1 },
|
|
20786
|
+
lightGoldenrod: { r: 0.980392, g: 0.980392, b: 0.823529, a: 1 },
|
|
20787
|
+
lightGray: { r: 0.827451, g: 0.827451, b: 0.827451, a: 1 },
|
|
20788
|
+
lightGreen: { r: 0.564706, g: 0.933333, b: 0.564706, a: 1 },
|
|
20789
|
+
lightPink: { r: 1, g: 0.713726, b: 0.756863, a: 1 },
|
|
20790
|
+
lightSalmon: { r: 1, g: 0.627451, b: 0.478431, a: 1 },
|
|
20791
|
+
lightSeaGreen: { r: 0.12549, g: 0.698039, b: 0.666667, a: 1 },
|
|
20792
|
+
lightSkyBlue: { r: 0.529412, g: 0.807843, b: 0.980392, a: 1 },
|
|
20793
|
+
lightSlateGray: { r: 0.466667, g: 0.533333, b: 0.6, a: 1 },
|
|
20794
|
+
lightSteelBlue: { r: 0.690196, g: 0.768627, b: 0.870588, a: 1 },
|
|
20795
|
+
lightYellow: { r: 1, g: 1, b: 0.878431, a: 1 },
|
|
20796
|
+
lime: { r: 0, g: 1, b: 0, a: 1 },
|
|
20797
|
+
limeGreen: { r: 0.196078, g: 0.803922, b: 0.196078, a: 1 },
|
|
20798
|
+
linen: { r: 0.980392, g: 0.941176, b: 0.901961, a: 1 },
|
|
20799
|
+
magenta: { r: 1, g: 0, b: 1, a: 1 },
|
|
20800
|
+
maroon: { r: 0.690196, g: 0.188235, b: 0.376471, a: 1 },
|
|
20801
|
+
mediumAquamarine: { r: 0.4, g: 0.803922, b: 0.666667, a: 1 },
|
|
20802
|
+
mediumBlue: { r: 0, g: 0, b: 0.803922, a: 1 },
|
|
20803
|
+
mediumOrchid: { r: 0.729412, g: 0.333333, b: 0.827451, a: 1 },
|
|
20804
|
+
mediumPurple: { r: 0.576471, g: 0.439216, b: 0.858824, a: 1 },
|
|
20805
|
+
mediumSeaGreen: { r: 0.235294, g: 0.701961, b: 0.443137, a: 1 },
|
|
20806
|
+
mediumSlateBlue: { r: 0.482353, g: 0.407843, b: 0.933333, a: 1 },
|
|
20807
|
+
mediumSpringGreen: { r: 0, g: 0.980392, b: 0.603922, a: 1 },
|
|
20808
|
+
mediumTurquoise: { r: 0.282353, g: 0.819608, b: 0.8, a: 1 },
|
|
20809
|
+
mediumVioletRed: { r: 0.780392, g: 0.0823529, b: 0.521569, a: 1 },
|
|
20810
|
+
midnightBlue: { r: 0.0980392, g: 0.0980392, b: 0.439216, a: 1 },
|
|
20811
|
+
mintCream: { r: 0.960784, g: 1, b: 0.980392, a: 1 },
|
|
20812
|
+
mistyRose: { r: 1, g: 0.894118, b: 0.882353, a: 1 },
|
|
20813
|
+
moccasin: { r: 1, g: 0.894118, b: 0.709804, a: 1 },
|
|
20814
|
+
navyBlue: { r: 0, g: 0, b: 0.501961, a: 1 },
|
|
20815
|
+
oldLace: { r: 0.992157, g: 0.960784, b: 0.901961, a: 1 },
|
|
20816
|
+
olive: { r: 0.501961, g: 0.501961, b: 0, a: 1 },
|
|
20817
|
+
oliveDrab: { r: 0.419608, g: 0.556863, b: 0.137255, a: 1 },
|
|
20818
|
+
orange: { r: 1, g: 0.647059, b: 0, a: 1 },
|
|
20819
|
+
orangeRed: { r: 1, g: 0.270588, b: 0, a: 1 },
|
|
20820
|
+
orchid: { r: 0.854902, g: 0.439216, b: 0.839216, a: 1 },
|
|
20821
|
+
paleGoldenrod: { r: 0.933333, g: 0.909804, b: 0.666667, a: 1 },
|
|
20822
|
+
paleGreen: { r: 0.596078, g: 0.984314, b: 0.596078, a: 1 },
|
|
20823
|
+
paleTurquoise: { r: 0.686275, g: 0.933333, b: 0.933333, a: 1 },
|
|
20824
|
+
paleVioletRed: { r: 0.858824, g: 0.439216, b: 0.576471, a: 1 },
|
|
20825
|
+
papayaWhip: { r: 1, g: 0.937255, b: 0.835294, a: 1 },
|
|
20826
|
+
peachPuff: { r: 1, g: 0.854902, b: 0.72549, a: 1 },
|
|
20827
|
+
peru: { r: 0.803922, g: 0.521569, b: 0.247059, a: 1 },
|
|
20828
|
+
pink: { r: 1, g: 0.752941, b: 0.796078, a: 1 },
|
|
20829
|
+
plum: { r: 0.866667, g: 0.627451, b: 0.866667, a: 1 },
|
|
20830
|
+
powderBlue: { r: 0.690196, g: 0.878431, b: 0.901961, a: 1 },
|
|
20831
|
+
purple: { r: 0.627451, g: 0.12549, b: 0.941176, a: 1 },
|
|
20832
|
+
rebeccaPurple: { r: 0.4, g: 0.2, b: 0.6, a: 1 },
|
|
20833
|
+
red: { r: 1, g: 0, b: 0, a: 1 },
|
|
20834
|
+
rosyBrown: { r: 0.737255, g: 0.560784, b: 0.560784, a: 1 },
|
|
20835
|
+
royalBlue: { r: 0.254902, g: 0.411765, b: 0.882353, a: 1 },
|
|
20836
|
+
saddleBrown: { r: 0.545098, g: 0.270588, b: 0.0745098, a: 1 },
|
|
20837
|
+
salmon: { r: 0.980392, g: 0.501961, b: 0.447059, a: 1 },
|
|
20838
|
+
sandyBrown: { r: 0.956863, g: 0.643137, b: 0.376471, a: 1 },
|
|
20839
|
+
seaGreen: { r: 0.180392, g: 0.545098, b: 0.341176, a: 1 },
|
|
20840
|
+
seashell: { r: 1, g: 0.960784, b: 0.933333, a: 1 },
|
|
20841
|
+
sienna: { r: 0.627451, g: 0.321569, b: 0.176471, a: 1 },
|
|
20842
|
+
silver: { r: 0.752941, g: 0.752941, b: 0.752941, a: 1 },
|
|
20843
|
+
skyBlue: { r: 0.529412, g: 0.807843, b: 0.921569, a: 1 },
|
|
20844
|
+
slateBlue: { r: 0.415686, g: 0.352941, b: 0.803922, a: 1 },
|
|
20845
|
+
slateGray: { r: 0.439216, g: 0.501961, b: 0.564706, a: 1 },
|
|
20846
|
+
snow: { r: 1, g: 0.980392, b: 0.980392, a: 1 },
|
|
20847
|
+
springGreen: { r: 0, g: 1, b: 0.498039, a: 1 },
|
|
20848
|
+
steelBlue: { r: 0.27451, g: 0.509804, b: 0.705882, a: 1 },
|
|
20849
|
+
tan: { r: 0.823529, g: 0.705882, b: 0.54902, a: 1 },
|
|
20850
|
+
teal: { r: 0, g: 0.501961, b: 0.501961, a: 1 },
|
|
20851
|
+
thistle: { r: 0.847059, g: 0.74902, b: 0.847059, a: 1 },
|
|
20852
|
+
tomato: { r: 1, g: 0.388235, b: 0.278431, a: 1 },
|
|
20853
|
+
transparent: { r: 1, g: 1, b: 1, a: 0 },
|
|
20854
|
+
turquoise: { r: 0.25098, g: 0.878431, b: 0.815686, a: 1 },
|
|
20855
|
+
violet: { r: 0.933333, g: 0.509804, b: 0.933333, a: 1 },
|
|
20856
|
+
webGray: { r: 0.501961, g: 0.501961, b: 0.501961, a: 1 },
|
|
20857
|
+
webGreen: { r: 0, g: 0.501961, b: 0, a: 1 },
|
|
20858
|
+
webMaroon: { r: 0.501961, g: 0, b: 0, a: 1 },
|
|
20859
|
+
webPurple: { r: 0.501961, g: 0, b: 0.501961, a: 1 },
|
|
20860
|
+
wheat: { r: 0.960784, g: 0.870588, b: 0.701961, a: 1 },
|
|
20861
|
+
white: { r: 1, g: 1, b: 1, a: 1 },
|
|
20862
|
+
whiteSmoke: { r: 0.960784, g: 0.960784, b: 0.960784, a: 1 },
|
|
20863
|
+
yellow: { r: 1, g: 1, b: 0, a: 1 },
|
|
20864
|
+
yellowGreen: { r: 0.603922, g: 0.803922, b: 0.196078, a: 1 }
|
|
20865
|
+
});
|
|
20866
|
+
// src/math/mod.ts
|
|
20867
|
+
var exports_mod4 = {};
|
|
20868
|
+
__export(exports_mod4, {
|
|
20869
|
+
transformPoint: () => transformPoint,
|
|
20870
|
+
rad2deg: () => rad2deg,
|
|
20871
|
+
deg2rad: () => deg2rad,
|
|
20872
|
+
createViewMatrix: () => createViewMatrix,
|
|
20873
|
+
createProjectionMatrix: () => createProjectionMatrix,
|
|
20874
|
+
createModelMatrix: () => createModelMatrix,
|
|
20875
|
+
convertWorldToScreen: () => convertWorldToScreen,
|
|
20876
|
+
convertScreenToWorld: () => convertScreenToWorld
|
|
20877
|
+
});
|
|
20878
|
+
// src/scene/mod.ts
|
|
20879
|
+
var exports_mod5 = {};
|
|
20880
|
+
__export(exports_mod5, {
|
|
20881
|
+
TextNode: () => TextNode,
|
|
20882
|
+
SceneNode: () => SceneNode,
|
|
20883
|
+
QuadNode: () => QuadNode,
|
|
20884
|
+
DEFAULT_FONT_SIZE: () => DEFAULT_FONT_SIZE,
|
|
20885
|
+
Camera: () => Camera
|
|
20886
|
+
});
|
|
20887
|
+
// src/screen/mod.ts
|
|
20888
|
+
var exports_mod6 = {};
|
|
20889
|
+
// src/text/mod.ts
|
|
20890
|
+
var exports_mod7 = {};
|
|
20891
|
+
__export(exports_mod7, {
|
|
20892
|
+
TextShader: () => WebGPUTextShader
|
|
20893
|
+
});
|
|
20894
|
+
// src/textures/mod.ts
|
|
20895
|
+
var exports_mod8 = {};
|
|
20896
|
+
__export(exports_mod8, {
|
|
20897
|
+
Bundles: () => Bundles
|
|
20898
|
+
});
|
|
20620
20899
|
export {
|
|
20621
|
-
Utils,
|
|
20900
|
+
exports_mod2 as Utils,
|
|
20622
20901
|
Toodle,
|
|
20623
|
-
Textures,
|
|
20624
|
-
Text,
|
|
20625
|
-
Screen,
|
|
20626
|
-
Scene,
|
|
20627
|
-
GfxMath,
|
|
20902
|
+
exports_mod8 as Textures,
|
|
20903
|
+
exports_mod7 as Text,
|
|
20904
|
+
exports_mod6 as Screen,
|
|
20905
|
+
exports_mod5 as Scene,
|
|
20906
|
+
exports_mod4 as GfxMath,
|
|
20628
20907
|
DEFAULT_LIMITS,
|
|
20629
|
-
Colors,
|
|
20630
|
-
|
|
20631
|
-
Backends,
|
|
20632
|
-
|
|
20908
|
+
exports_mod3 as Colors,
|
|
20909
|
+
Bundles,
|
|
20910
|
+
exports_mod as Backends,
|
|
20911
|
+
AssetManager
|
|
20633
20912
|
};
|
|
20634
20913
|
|
|
20635
|
-
//# debugId=
|
|
20914
|
+
//# debugId=18E70D7AC0F5250F64756E2164756E21
|
|
20636
20915
|
//# sourceMappingURL=mod.js.map
|