@bloopjs/toodle 0.0.102 → 0.0.104
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/Toodle.d.ts +9 -1
- package/dist/Toodle.d.ts.map +1 -1
- package/dist/mod.d.ts +1 -0
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +340 -159
- package/dist/mod.js.map +9 -8
- package/dist/scene/QuadNode.d.ts.map +1 -1
- package/dist/scene/SceneNode.d.ts +2 -2
- package/dist/scene/SceneNode.d.ts.map +1 -1
- package/dist/textures/AssetManager.d.ts +10 -2
- package/dist/textures/AssetManager.d.ts.map +1 -1
- package/dist/textures/Bundles.d.ts +183 -0
- package/dist/textures/Bundles.d.ts.map +1 -0
- package/dist/textures/mod.d.ts +2 -0
- package/dist/textures/mod.d.ts.map +1 -1
- package/dist/textures/types.d.ts +4 -2
- package/dist/textures/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/Toodle.ts +31 -15
- package/src/mod.ts +1 -0
- package/src/scene/QuadNode.ts +1 -4
- package/src/scene/SceneNode.ts +11 -12
- package/src/text/TextNode.ts +2 -2
- package/src/textures/AssetManager.ts +44 -195
- package/src/textures/Bundles.ts +541 -0
- package/src/textures/mod.ts +2 -0
- package/src/textures/types.ts +4 -2
package/dist/mod.js
CHANGED
|
@@ -3611,7 +3611,7 @@ class SceneNode {
|
|
|
3611
3611
|
#transform;
|
|
3612
3612
|
#matrix = mat3.identity();
|
|
3613
3613
|
#renderComponent = null;
|
|
3614
|
-
#
|
|
3614
|
+
#size = null;
|
|
3615
3615
|
#positionProxy;
|
|
3616
3616
|
#scaleProxy;
|
|
3617
3617
|
#cache = null;
|
|
@@ -3623,7 +3623,7 @@ class SceneNode {
|
|
|
3623
3623
|
this.#transform = {
|
|
3624
3624
|
position: opts?.position ?? { x: 0, y: 0 },
|
|
3625
3625
|
scale: { x: 1, y: 1 },
|
|
3626
|
-
size: opts?.
|
|
3626
|
+
size: opts?.size ?? { width: 1, height: 1 },
|
|
3627
3627
|
rotation: opts?.rotationRadians ?? 0
|
|
3628
3628
|
};
|
|
3629
3629
|
if (opts?.scale)
|
|
@@ -3635,7 +3635,7 @@ class SceneNode {
|
|
|
3635
3635
|
this.#layer = opts?.layer ?? null;
|
|
3636
3636
|
this.#isActive = opts?.isActive ?? true;
|
|
3637
3637
|
this.label = opts?.label ?? undefined;
|
|
3638
|
-
this.#
|
|
3638
|
+
this.#size = opts?.size ?? null;
|
|
3639
3639
|
this.#key = opts?.key ?? null;
|
|
3640
3640
|
for (const kid of opts?.kids ?? []) {
|
|
3641
3641
|
this.add(kid);
|
|
@@ -3745,19 +3745,19 @@ class SceneNode {
|
|
|
3745
3745
|
}
|
|
3746
3746
|
this.setDirty();
|
|
3747
3747
|
}
|
|
3748
|
-
set
|
|
3749
|
-
this.#
|
|
3748
|
+
set size(value) {
|
|
3749
|
+
this.#size = value;
|
|
3750
3750
|
this.setDirty();
|
|
3751
3751
|
}
|
|
3752
3752
|
get size() {
|
|
3753
|
-
return this.#
|
|
3753
|
+
return this.#size;
|
|
3754
3754
|
}
|
|
3755
3755
|
get aspectRatio() {
|
|
3756
|
-
if (!this.#
|
|
3756
|
+
if (!this.#size) {
|
|
3757
3757
|
console.warn("Attempted to get aspect ratio of a node with no ideal size");
|
|
3758
3758
|
return 1;
|
|
3759
3759
|
}
|
|
3760
|
-
return this.#
|
|
3760
|
+
return this.#size.width / this.#size.height;
|
|
3761
3761
|
}
|
|
3762
3762
|
get isActive() {
|
|
3763
3763
|
if (!this.#cache?.isActive) {
|
|
@@ -3964,7 +3964,7 @@ class QuadNode extends SceneNode {
|
|
|
3964
3964
|
#writeInstance;
|
|
3965
3965
|
constructor(options, matrixPool) {
|
|
3966
3966
|
assert(options.shader, "QuadNode requires a shader to be explicitly provided");
|
|
3967
|
-
assert(options.
|
|
3967
|
+
assert(options.size, "QuadNode requires a size to be explicitly provided");
|
|
3968
3968
|
assert(options.atlasCoords, "QuadNode requires atlas coords to be explicitly provided");
|
|
3969
3969
|
options.render ??= {
|
|
3970
3970
|
shader: options.shader,
|
|
@@ -17570,8 +17570,8 @@ class TextNode extends SceneNode {
|
|
|
17570
17570
|
throw new Error(`Text: ${text} exceeds ${shader.maxCharCount} characters. Try using fewer characters or increase the limit in Toodle.attach.`);
|
|
17571
17571
|
}
|
|
17572
17572
|
const em2px = shader.font.lineHeight / (opts.fontSize ?? DEFAULT_FONT_SIZE);
|
|
17573
|
-
if (!opts.shrinkToFit && !opts.
|
|
17574
|
-
opts.
|
|
17573
|
+
if (!opts.shrinkToFit && !opts.size) {
|
|
17574
|
+
opts.size = { width: width / em2px, height: height / em2px };
|
|
17575
17575
|
}
|
|
17576
17576
|
super({
|
|
17577
17577
|
...opts,
|
|
@@ -18088,6 +18088,276 @@ class Pool {
|
|
|
18088
18088
|
this.#index = 0;
|
|
18089
18089
|
}
|
|
18090
18090
|
}
|
|
18091
|
+
// src/textures/Bundles.ts
|
|
18092
|
+
class Bundles {
|
|
18093
|
+
#bundles = new Map;
|
|
18094
|
+
#textures = new Map;
|
|
18095
|
+
#atlasSize;
|
|
18096
|
+
constructor(options = {}) {
|
|
18097
|
+
this.#atlasSize = options.atlasSize ?? 4096;
|
|
18098
|
+
}
|
|
18099
|
+
async registerAtlasBundle(bundleId, opts) {
|
|
18100
|
+
const atlases = [];
|
|
18101
|
+
for (const atlas of opts.atlases) {
|
|
18102
|
+
const jsonUrl = atlas.json ?? new URL(atlas.png.toString().replace(".png", ".json"), atlas.png.origin);
|
|
18103
|
+
const pngUrl = atlas.png ?? new URL(atlas.json.toString().replace(".json", ".png"), atlas.json.origin);
|
|
18104
|
+
const atlasDef = await (await fetch(jsonUrl)).json();
|
|
18105
|
+
const bitmap = !opts.rg8 ? await this.#getBitmapFromUrl(pngUrl) : await createImageBitmap(new ImageData(1, 1));
|
|
18106
|
+
let rg8Bytes;
|
|
18107
|
+
if (opts.rg8) {
|
|
18108
|
+
const rg8url = new URL(pngUrl.toString().replace(".png", ".rg8.gz"), pngUrl.origin);
|
|
18109
|
+
rg8Bytes = await this.#fetchRg8Bytes(rg8url);
|
|
18110
|
+
}
|
|
18111
|
+
const cpuTextureAtlas = {
|
|
18112
|
+
texture: bitmap,
|
|
18113
|
+
rg8Bytes,
|
|
18114
|
+
textureRegions: new Map,
|
|
18115
|
+
width: opts.rg8 ? this.#atlasSize : bitmap.width,
|
|
18116
|
+
height: opts.rg8 ? this.#atlasSize : bitmap.height
|
|
18117
|
+
};
|
|
18118
|
+
for (const [assetId, frame] of Object.entries(atlasDef.frames)) {
|
|
18119
|
+
const textureRegion = this.#parsePixiFrame(frame, cpuTextureAtlas.width, cpuTextureAtlas.height);
|
|
18120
|
+
cpuTextureAtlas.textureRegions.set(assetId, textureRegion);
|
|
18121
|
+
}
|
|
18122
|
+
atlases.push(cpuTextureAtlas);
|
|
18123
|
+
}
|
|
18124
|
+
this.#bundles.set(bundleId, {
|
|
18125
|
+
atlases,
|
|
18126
|
+
atlasIndices: [],
|
|
18127
|
+
isLoaded: false
|
|
18128
|
+
});
|
|
18129
|
+
return bundleId;
|
|
18130
|
+
}
|
|
18131
|
+
registerDynamicBundle(bundleId, atlases) {
|
|
18132
|
+
this.#bundles.set(bundleId, {
|
|
18133
|
+
atlases,
|
|
18134
|
+
atlasIndices: [],
|
|
18135
|
+
isLoaded: false
|
|
18136
|
+
});
|
|
18137
|
+
}
|
|
18138
|
+
hasBundle(bundleId) {
|
|
18139
|
+
return this.#bundles.has(bundleId);
|
|
18140
|
+
}
|
|
18141
|
+
isBundleLoaded(bundleId) {
|
|
18142
|
+
const bundle = this.#bundles.get(bundleId);
|
|
18143
|
+
return bundle?.isLoaded ?? false;
|
|
18144
|
+
}
|
|
18145
|
+
getBundleAtlasIndices(bundleId) {
|
|
18146
|
+
const bundle = this.#bundles.get(bundleId);
|
|
18147
|
+
return bundle?.atlasIndices ?? [];
|
|
18148
|
+
}
|
|
18149
|
+
setBundleLoaded(bundleId, atlasIndices) {
|
|
18150
|
+
const bundle = this.#bundles.get(bundleId);
|
|
18151
|
+
if (!bundle) {
|
|
18152
|
+
throw new Error(`Bundle ${bundleId} not found`);
|
|
18153
|
+
}
|
|
18154
|
+
bundle.atlasIndices = atlasIndices;
|
|
18155
|
+
bundle.isLoaded = true;
|
|
18156
|
+
}
|
|
18157
|
+
markBundleLoaded(bundleId, atlasIndices) {
|
|
18158
|
+
const bundle = this.#bundles.get(bundleId);
|
|
18159
|
+
if (!bundle) {
|
|
18160
|
+
throw new Error(`Bundle ${bundleId} not found`);
|
|
18161
|
+
}
|
|
18162
|
+
if (bundle.isLoaded) {
|
|
18163
|
+
console.warn(`Bundle ${bundleId} is already loaded.`);
|
|
18164
|
+
return;
|
|
18165
|
+
}
|
|
18166
|
+
const indices = atlasIndices ?? bundle.atlases.map(() => this.#getNextAtlasIndex());
|
|
18167
|
+
if (indices.length !== bundle.atlases.length) {
|
|
18168
|
+
throw new Error(`Expected ${bundle.atlases.length} atlas indices, got ${indices.length}`);
|
|
18169
|
+
}
|
|
18170
|
+
for (let i3 = 0;i3 < bundle.atlases.length; i3++) {
|
|
18171
|
+
const atlas = bundle.atlases[i3];
|
|
18172
|
+
const atlasIndex = indices[i3];
|
|
18173
|
+
bundle.atlasIndices.push(atlasIndex);
|
|
18174
|
+
for (const [id, region] of atlas.textureRegions) {
|
|
18175
|
+
const coords = { ...region, atlasIndex };
|
|
18176
|
+
const existing = this.#textures.get(id);
|
|
18177
|
+
if (existing) {
|
|
18178
|
+
existing.push(coords);
|
|
18179
|
+
} else {
|
|
18180
|
+
this.#textures.set(id, [coords]);
|
|
18181
|
+
}
|
|
18182
|
+
}
|
|
18183
|
+
}
|
|
18184
|
+
bundle.isLoaded = true;
|
|
18185
|
+
}
|
|
18186
|
+
unloadBundle(bundleId) {
|
|
18187
|
+
const bundle = this.#bundles.get(bundleId);
|
|
18188
|
+
if (!bundle) {
|
|
18189
|
+
throw new Error(`Bundle ${bundleId} not found`);
|
|
18190
|
+
}
|
|
18191
|
+
if (!bundle.isLoaded) {
|
|
18192
|
+
console.warn(`Bundle ${bundleId} is not loaded.`);
|
|
18193
|
+
return;
|
|
18194
|
+
}
|
|
18195
|
+
for (const atlasIndex of bundle.atlasIndices) {
|
|
18196
|
+
for (const [id, coords] of this.#textures.entries()) {
|
|
18197
|
+
const indexToRemove = coords.findIndex((coord) => coord.atlasIndex === atlasIndex);
|
|
18198
|
+
if (indexToRemove !== -1) {
|
|
18199
|
+
coords.splice(indexToRemove, 1);
|
|
18200
|
+
}
|
|
18201
|
+
if (!coords.length) {
|
|
18202
|
+
this.#textures.delete(id);
|
|
18203
|
+
}
|
|
18204
|
+
}
|
|
18205
|
+
}
|
|
18206
|
+
bundle.isLoaded = false;
|
|
18207
|
+
bundle.atlasIndices = [];
|
|
18208
|
+
}
|
|
18209
|
+
get textures() {
|
|
18210
|
+
return this.#textures;
|
|
18211
|
+
}
|
|
18212
|
+
get textureIds() {
|
|
18213
|
+
return Array.from(this.#textures.keys());
|
|
18214
|
+
}
|
|
18215
|
+
getAtlasCoords(id) {
|
|
18216
|
+
const coords = this.#textures.get(id);
|
|
18217
|
+
if (!coords) {
|
|
18218
|
+
throw new Error(`Texture ${id} not found. Have you registered and loaded a bundle containing this texture?`);
|
|
18219
|
+
}
|
|
18220
|
+
return coords;
|
|
18221
|
+
}
|
|
18222
|
+
setAtlasCoords(id, coords) {
|
|
18223
|
+
const oldCoords = this.#textures.get(id);
|
|
18224
|
+
if (!oldCoords)
|
|
18225
|
+
return;
|
|
18226
|
+
const indexToModify = oldCoords.findIndex((coord) => coord.atlasIndex === coords.atlasIndex);
|
|
18227
|
+
if (indexToModify === -1)
|
|
18228
|
+
return;
|
|
18229
|
+
oldCoords[indexToModify] = coords;
|
|
18230
|
+
this.#textures.set(id, oldCoords);
|
|
18231
|
+
}
|
|
18232
|
+
addTextureEntry(id, coords) {
|
|
18233
|
+
const existing = this.#textures.get(id);
|
|
18234
|
+
if (existing) {
|
|
18235
|
+
existing.push(coords);
|
|
18236
|
+
} else {
|
|
18237
|
+
this.#textures.set(id, [coords]);
|
|
18238
|
+
}
|
|
18239
|
+
}
|
|
18240
|
+
removeTextureEntriesForAtlas(atlasIndex) {
|
|
18241
|
+
for (const [id, coords] of this.#textures.entries()) {
|
|
18242
|
+
const indexToRemove = coords.findIndex((coord) => coord.atlasIndex === atlasIndex);
|
|
18243
|
+
if (indexToRemove !== -1) {
|
|
18244
|
+
coords.splice(indexToRemove, 1);
|
|
18245
|
+
}
|
|
18246
|
+
if (!coords.length) {
|
|
18247
|
+
this.#textures.delete(id);
|
|
18248
|
+
}
|
|
18249
|
+
}
|
|
18250
|
+
}
|
|
18251
|
+
getTextureRegion(id) {
|
|
18252
|
+
const coords = this.#textures.get(id);
|
|
18253
|
+
if (!coords || coords.length === 0)
|
|
18254
|
+
return;
|
|
18255
|
+
const { atlasIndex: _3, ...region } = coords[0];
|
|
18256
|
+
return region;
|
|
18257
|
+
}
|
|
18258
|
+
getTextureOffset(id) {
|
|
18259
|
+
const coords = this.#textures.get(id);
|
|
18260
|
+
if (!coords) {
|
|
18261
|
+
throw new Error(`Texture ${id} not found. Have you registered and loaded a bundle containing this texture?`);
|
|
18262
|
+
}
|
|
18263
|
+
return coords[0].cropOffset;
|
|
18264
|
+
}
|
|
18265
|
+
getSize(id) {
|
|
18266
|
+
const coords = this.getAtlasCoords(id);
|
|
18267
|
+
const uvScale = coords[0].uvScale;
|
|
18268
|
+
return {
|
|
18269
|
+
width: uvScale.width * this.#atlasSize,
|
|
18270
|
+
height: uvScale.height * this.#atlasSize
|
|
18271
|
+
};
|
|
18272
|
+
}
|
|
18273
|
+
getCroppedSize(id) {
|
|
18274
|
+
const coords = this.getAtlasCoords(id);
|
|
18275
|
+
const uvScaleCropped = coords[0].uvScaleCropped;
|
|
18276
|
+
if (uvScaleCropped) {
|
|
18277
|
+
return {
|
|
18278
|
+
width: uvScaleCropped.width * this.#atlasSize,
|
|
18279
|
+
height: uvScaleCropped.height * this.#atlasSize
|
|
18280
|
+
};
|
|
18281
|
+
}
|
|
18282
|
+
return this.getSize(id);
|
|
18283
|
+
}
|
|
18284
|
+
hasTexture(id) {
|
|
18285
|
+
return this.#textures.has(id);
|
|
18286
|
+
}
|
|
18287
|
+
getRegisteredBundleIds() {
|
|
18288
|
+
return Array.from(this.#bundles.keys());
|
|
18289
|
+
}
|
|
18290
|
+
getLoadedBundleIds() {
|
|
18291
|
+
return Array.from(this.#bundles.entries()).filter(([, bundle]) => bundle.isLoaded).map(([id]) => id);
|
|
18292
|
+
}
|
|
18293
|
+
getBundleAtlases(bundleId) {
|
|
18294
|
+
const bundle = this.#bundles.get(bundleId);
|
|
18295
|
+
if (!bundle) {
|
|
18296
|
+
throw new Error(`Bundle ${bundleId} not found`);
|
|
18297
|
+
}
|
|
18298
|
+
return bundle.atlases;
|
|
18299
|
+
}
|
|
18300
|
+
get atlasSize() {
|
|
18301
|
+
return this.#atlasSize;
|
|
18302
|
+
}
|
|
18303
|
+
#parsePixiFrame(frame, atlasWidth, atlasHeight) {
|
|
18304
|
+
const leftCrop = frame.spriteSourceSize.x;
|
|
18305
|
+
const rightCrop = frame.sourceSize.w - frame.spriteSourceSize.x - frame.spriteSourceSize.w;
|
|
18306
|
+
const topCrop = frame.spriteSourceSize.y;
|
|
18307
|
+
const bottomCrop = frame.sourceSize.h - frame.spriteSourceSize.y - frame.spriteSourceSize.h;
|
|
18308
|
+
return {
|
|
18309
|
+
cropOffset: {
|
|
18310
|
+
x: leftCrop - rightCrop,
|
|
18311
|
+
y: bottomCrop - topCrop
|
|
18312
|
+
},
|
|
18313
|
+
originalSize: {
|
|
18314
|
+
width: frame.sourceSize.w,
|
|
18315
|
+
height: frame.sourceSize.h
|
|
18316
|
+
},
|
|
18317
|
+
uvOffset: {
|
|
18318
|
+
x: frame.frame.x / atlasWidth,
|
|
18319
|
+
y: frame.frame.y / atlasHeight
|
|
18320
|
+
},
|
|
18321
|
+
uvScale: {
|
|
18322
|
+
width: frame.sourceSize.w / atlasWidth,
|
|
18323
|
+
height: frame.sourceSize.h / atlasHeight
|
|
18324
|
+
},
|
|
18325
|
+
uvScaleCropped: {
|
|
18326
|
+
width: frame.frame.w / atlasWidth,
|
|
18327
|
+
height: frame.frame.h / atlasHeight
|
|
18328
|
+
}
|
|
18329
|
+
};
|
|
18330
|
+
}
|
|
18331
|
+
async#getBitmapFromUrl(url) {
|
|
18332
|
+
const response = await fetch(url);
|
|
18333
|
+
const blob = await response.blob();
|
|
18334
|
+
return createImageBitmap(blob);
|
|
18335
|
+
}
|
|
18336
|
+
async#fetchRg8Bytes(url) {
|
|
18337
|
+
const response = await fetch(url);
|
|
18338
|
+
const enc = (response.headers.get("content-encoding") || "").toLowerCase();
|
|
18339
|
+
if (enc.includes("gzip") || enc.includes("br") || enc.includes("deflate")) {
|
|
18340
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
18341
|
+
}
|
|
18342
|
+
if (!response.body) {
|
|
18343
|
+
throw new Error("Response body of rg8 file is null");
|
|
18344
|
+
}
|
|
18345
|
+
const ds = new DecompressionStream("gzip");
|
|
18346
|
+
const ab = await new Response(response.body.pipeThrough(ds)).arrayBuffer();
|
|
18347
|
+
return new Uint8Array(ab);
|
|
18348
|
+
}
|
|
18349
|
+
#getNextAtlasIndex() {
|
|
18350
|
+
let maxIndex = -1;
|
|
18351
|
+
for (const bundle of this.#bundles.values()) {
|
|
18352
|
+
for (const idx of bundle.atlasIndices) {
|
|
18353
|
+
if (idx > maxIndex)
|
|
18354
|
+
maxIndex = idx;
|
|
18355
|
+
}
|
|
18356
|
+
}
|
|
18357
|
+
return maxIndex + 1;
|
|
18358
|
+
}
|
|
18359
|
+
}
|
|
18360
|
+
|
|
18091
18361
|
// src/textures/pixel-scraping.wgsl.ts
|
|
18092
18362
|
var pixel_scraping_wgsl_default = `
|
|
18093
18363
|
// ==============================
|
|
@@ -18650,18 +18920,19 @@ async function textureToBitmap(device, texture, width, height) {
|
|
|
18650
18920
|
// src/textures/AssetManager.ts
|
|
18651
18921
|
class AssetManager {
|
|
18652
18922
|
textureAtlas;
|
|
18923
|
+
bundles;
|
|
18653
18924
|
#device;
|
|
18654
18925
|
#presentationFormat;
|
|
18655
|
-
#bundles = new Map;
|
|
18656
|
-
#textures = new Map;
|
|
18657
18926
|
#fonts = new Map;
|
|
18658
18927
|
#cropComputeShader;
|
|
18659
18928
|
#limits;
|
|
18660
18929
|
#availableIndices = new Set;
|
|
18661
|
-
constructor(device, presentationFormat, limits,
|
|
18930
|
+
constructor(device, presentationFormat, limits, options = {}) {
|
|
18662
18931
|
this.#device = device;
|
|
18663
18932
|
this.#presentationFormat = presentationFormat;
|
|
18664
18933
|
this.#limits = limits;
|
|
18934
|
+
this.bundles = options.bundles ?? new Bundles({ atlasSize: limits.textureSize });
|
|
18935
|
+
const format = options.format ?? "rgba8unorm";
|
|
18665
18936
|
this.textureAtlas = device.createTexture({
|
|
18666
18937
|
label: "Asset Manager Atlas Texture",
|
|
18667
18938
|
size: [
|
|
@@ -18694,16 +18965,16 @@ class AssetManager {
|
|
|
18694
18965
|
return this.getSize(id);
|
|
18695
18966
|
}
|
|
18696
18967
|
isCropped(id) {
|
|
18697
|
-
if (!this
|
|
18968
|
+
if (!this.bundles.hasTexture(id)) {
|
|
18698
18969
|
throw new Error(`Texture ${id} not found in atlas. Have you called toodle.loadTextures with this id or toodle.loadBundle with a bundle that contains it?`);
|
|
18699
18970
|
}
|
|
18700
|
-
return this
|
|
18971
|
+
return this.bundles.getAtlasCoords(id)[0].uvScaleCropped === undefined;
|
|
18701
18972
|
}
|
|
18702
18973
|
get textures() {
|
|
18703
|
-
return this
|
|
18974
|
+
return this.bundles.textures;
|
|
18704
18975
|
}
|
|
18705
18976
|
get textureIds() {
|
|
18706
|
-
return
|
|
18977
|
+
return this.bundles.textureIds;
|
|
18707
18978
|
}
|
|
18708
18979
|
async loadTextures(opts) {
|
|
18709
18980
|
await Promise.all(Object.entries(opts).map(([id, url]) => this.loadTexture(id, url, opts)));
|
|
@@ -18730,7 +19001,7 @@ class AssetManager {
|
|
|
18730
19001
|
},
|
|
18731
19002
|
atlasIndex
|
|
18732
19003
|
};
|
|
18733
|
-
this
|
|
19004
|
+
this.bundles.addTextureEntry(id, coords);
|
|
18734
19005
|
this.#availableIndices.delete(atlasIndex);
|
|
18735
19006
|
textureWrapper.texture.destroy();
|
|
18736
19007
|
return { id, coords };
|
|
@@ -18741,38 +19012,39 @@ class AssetManager {
|
|
|
18741
19012
|
} else {
|
|
18742
19013
|
await this.#registerBundleFromAtlases(bundleId, opts);
|
|
18743
19014
|
}
|
|
18744
|
-
|
|
19015
|
+
const autoLoad = opts.autoLoad ?? true;
|
|
19016
|
+
if (autoLoad) {
|
|
18745
19017
|
await this.loadBundle(bundleId);
|
|
18746
19018
|
}
|
|
18747
19019
|
return bundleId;
|
|
18748
19020
|
}
|
|
18749
19021
|
async loadBundle(bundleId) {
|
|
18750
|
-
|
|
18751
|
-
if (!bundle) {
|
|
19022
|
+
if (!this.bundles.hasBundle(bundleId)) {
|
|
18752
19023
|
throw new Error(`Bundle ${bundleId} not found`);
|
|
18753
19024
|
}
|
|
18754
|
-
if (
|
|
19025
|
+
if (this.bundles.isBundleLoaded(bundleId)) {
|
|
18755
19026
|
console.warn(`Bundle ${bundleId} is already loaded.`);
|
|
18756
19027
|
return;
|
|
18757
19028
|
}
|
|
18758
|
-
|
|
19029
|
+
const atlases = this.bundles.getBundleAtlases(bundleId);
|
|
19030
|
+
const atlasIndices = [];
|
|
19031
|
+
for (const atlas of atlases) {
|
|
18759
19032
|
const atlasIndex = await this.extra.loadAtlas(atlas);
|
|
18760
|
-
|
|
19033
|
+
atlasIndices.push(atlasIndex);
|
|
18761
19034
|
}
|
|
18762
|
-
|
|
19035
|
+
this.bundles.setBundleLoaded(bundleId, atlasIndices);
|
|
18763
19036
|
}
|
|
18764
19037
|
async unloadBundle(bundleId) {
|
|
18765
|
-
|
|
18766
|
-
if (!bundle) {
|
|
19038
|
+
if (!this.bundles.hasBundle(bundleId)) {
|
|
18767
19039
|
throw new Error(`Bundle ${bundleId} not found`);
|
|
18768
19040
|
}
|
|
18769
|
-
if (!
|
|
19041
|
+
if (!this.bundles.isBundleLoaded(bundleId)) {
|
|
18770
19042
|
console.warn(`Bundle ${bundleId} is not loaded.`);
|
|
18771
19043
|
return;
|
|
18772
19044
|
}
|
|
18773
|
-
|
|
18774
|
-
|
|
18775
|
-
|
|
19045
|
+
const atlasIndices = this.bundles.getBundleAtlasIndices(bundleId);
|
|
19046
|
+
await Promise.all(atlasIndices.map((atlasIndex) => this.extra.unloadAtlas(atlasIndex)));
|
|
19047
|
+
this.bundles.unloadBundle(bundleId);
|
|
18776
19048
|
}
|
|
18777
19049
|
async loadFont(id, url, fallbackCharacter = "_") {
|
|
18778
19050
|
const font = await MsdfFont.create(id, url);
|
|
@@ -18791,22 +19063,14 @@ class AssetManager {
|
|
|
18791
19063
|
validateTextureReference(node) {
|
|
18792
19064
|
if (!(node instanceof QuadNode) || node.isPrimitive || node instanceof JumboQuadNode)
|
|
18793
19065
|
return;
|
|
18794
|
-
|
|
18795
|
-
if (!coords || !coords.length) {
|
|
19066
|
+
if (!this.bundles.hasTexture(node.textureId)) {
|
|
18796
19067
|
throw new Error(`Node ${node.id} references an invalid texture ${node.textureId}.`);
|
|
18797
19068
|
}
|
|
19069
|
+
const coords = this.bundles.getAtlasCoords(node.textureId);
|
|
18798
19070
|
if (coords.find((coord) => coord.atlasIndex === node.atlasCoords.atlasIndex))
|
|
18799
19071
|
return;
|
|
18800
19072
|
node.extra.setAtlasCoords(coords[0]);
|
|
18801
19073
|
}
|
|
18802
|
-
#addTexture(id, textureRegion, atlasIndex) {
|
|
18803
|
-
this.#textures.set(id, [
|
|
18804
|
-
{
|
|
18805
|
-
...textureRegion,
|
|
18806
|
-
atlasIndex
|
|
18807
|
-
}
|
|
18808
|
-
]);
|
|
18809
|
-
}
|
|
18810
19074
|
#createTextureFromImageBitmap(bitmap, name) {
|
|
18811
19075
|
const texture = this.#device.createTexture({
|
|
18812
19076
|
label: `${name} Intermediary Texture`,
|
|
@@ -18835,106 +19099,26 @@ class AssetManager {
|
|
|
18835
19099
|
images.set(id, textureWrapper);
|
|
18836
19100
|
}));
|
|
18837
19101
|
const atlases = await packBitmapsToAtlas(images, this.#limits.textureSize, this.#device);
|
|
18838
|
-
this
|
|
18839
|
-
atlases,
|
|
18840
|
-
atlasIndices: [],
|
|
18841
|
-
isLoaded: false
|
|
18842
|
-
});
|
|
19102
|
+
this.bundles.registerDynamicBundle(bundleId, atlases);
|
|
18843
19103
|
}
|
|
18844
19104
|
async#registerBundleFromAtlases(bundleId, opts) {
|
|
18845
|
-
|
|
18846
|
-
for (const atlas of opts.atlases) {
|
|
18847
|
-
const jsonUrl = atlas.json ?? new URL(atlas.png.toString().replace(".png", ".json"), atlas.png.origin);
|
|
18848
|
-
const pngUrl = atlas.png ?? new URL(atlas.json.toString().replace(".json", ".png"), atlas.json.origin);
|
|
18849
|
-
const atlasDef = await (await fetch(jsonUrl)).json();
|
|
18850
|
-
const bitmap = !opts.rg8 ? await getBitmapFromUrl(pngUrl) : await createImageBitmap(new ImageData(1, 1));
|
|
18851
|
-
let rg8Bytes;
|
|
18852
|
-
if (opts.rg8) {
|
|
18853
|
-
const rg8url = new URL(pngUrl.toString().replace(".png", ".rg8.gz"), pngUrl.origin);
|
|
18854
|
-
const rgBytes = await fetch(rg8url).then(async (r3) => {
|
|
18855
|
-
const enc = (r3.headers.get("content-encoding") || "").toLowerCase();
|
|
18856
|
-
if (enc.includes("gzip") || enc.includes("br") || enc.includes("deflate")) {
|
|
18857
|
-
return new Uint8Array(await r3.arrayBuffer());
|
|
18858
|
-
}
|
|
18859
|
-
assert(r3.body, "Response body of rg8 file is null");
|
|
18860
|
-
const ds = new DecompressionStream("gzip");
|
|
18861
|
-
const ab = await new Response(r3.body.pipeThrough(ds)).arrayBuffer();
|
|
18862
|
-
return new Uint8Array(ab);
|
|
18863
|
-
});
|
|
18864
|
-
rg8Bytes = rgBytes;
|
|
18865
|
-
}
|
|
18866
|
-
const cpuTextureAtlas = {
|
|
18867
|
-
texture: bitmap,
|
|
18868
|
-
rg8Bytes,
|
|
18869
|
-
textureRegions: new Map,
|
|
18870
|
-
width: opts.rg8 ? this.#limits.textureSize : bitmap.width,
|
|
18871
|
-
height: opts.rg8 ? this.#limits.textureSize : bitmap.height
|
|
18872
|
-
};
|
|
18873
|
-
for (const [assetId, frame] of Object.entries(atlasDef.frames)) {
|
|
18874
|
-
const leftCrop = frame.spriteSourceSize.x;
|
|
18875
|
-
const rightCrop = frame.sourceSize.w - frame.spriteSourceSize.x - frame.spriteSourceSize.w;
|
|
18876
|
-
const topCrop = frame.spriteSourceSize.y;
|
|
18877
|
-
const bottomCrop = frame.sourceSize.h - frame.spriteSourceSize.y - frame.spriteSourceSize.h;
|
|
18878
|
-
cpuTextureAtlas.textureRegions.set(assetId, {
|
|
18879
|
-
cropOffset: {
|
|
18880
|
-
x: leftCrop - rightCrop,
|
|
18881
|
-
y: bottomCrop - topCrop
|
|
18882
|
-
},
|
|
18883
|
-
originalSize: {
|
|
18884
|
-
width: frame.sourceSize.w,
|
|
18885
|
-
height: frame.sourceSize.h
|
|
18886
|
-
},
|
|
18887
|
-
uvOffset: {
|
|
18888
|
-
x: frame.frame.x / cpuTextureAtlas.width,
|
|
18889
|
-
y: frame.frame.y / cpuTextureAtlas.height
|
|
18890
|
-
},
|
|
18891
|
-
uvScale: {
|
|
18892
|
-
width: frame.sourceSize.w / cpuTextureAtlas.width,
|
|
18893
|
-
height: frame.sourceSize.h / cpuTextureAtlas.height
|
|
18894
|
-
},
|
|
18895
|
-
uvScaleCropped: {
|
|
18896
|
-
width: frame.frame.w / cpuTextureAtlas.width,
|
|
18897
|
-
height: frame.frame.h / cpuTextureAtlas.height
|
|
18898
|
-
}
|
|
18899
|
-
});
|
|
18900
|
-
}
|
|
18901
|
-
atlases.push(cpuTextureAtlas);
|
|
18902
|
-
}
|
|
18903
|
-
this.#bundles.set(bundleId, {
|
|
18904
|
-
atlases,
|
|
18905
|
-
atlasIndices: [],
|
|
18906
|
-
isLoaded: false
|
|
18907
|
-
});
|
|
19105
|
+
await this.bundles.registerAtlasBundle(bundleId, opts);
|
|
18908
19106
|
}
|
|
18909
19107
|
extra = {
|
|
18910
19108
|
getRegisteredBundleIds: () => {
|
|
18911
|
-
return this
|
|
19109
|
+
return this.bundles.getRegisteredBundleIds();
|
|
18912
19110
|
},
|
|
18913
19111
|
getLoadedBundleIds: () => {
|
|
18914
|
-
return
|
|
19112
|
+
return this.bundles.getLoadedBundleIds();
|
|
18915
19113
|
},
|
|
18916
19114
|
setAtlasCoords: (id, coords) => {
|
|
18917
|
-
|
|
18918
|
-
if (!oldCoords)
|
|
18919
|
-
return;
|
|
18920
|
-
const indexToModify = oldCoords.findIndex((coord) => coord.atlasIndex === coords.atlasIndex);
|
|
18921
|
-
if (indexToModify === -1)
|
|
18922
|
-
return;
|
|
18923
|
-
oldCoords[indexToModify] = coords;
|
|
18924
|
-
this.#textures.set(id, oldCoords);
|
|
19115
|
+
this.bundles.setAtlasCoords(id, coords);
|
|
18925
19116
|
},
|
|
18926
19117
|
getAtlasCoords: (id) => {
|
|
18927
|
-
|
|
18928
|
-
throw new Error(`Texture ${id} not found in atlas. Have you called toodle.loadBundle with a bundle that contains this id (or toodle.loadTextures with this id as a key)?`);
|
|
18929
|
-
}
|
|
18930
|
-
return this.#textures.get(id) ?? [];
|
|
19118
|
+
return this.bundles.getAtlasCoords(id);
|
|
18931
19119
|
},
|
|
18932
19120
|
getTextureOffset: (id) => {
|
|
18933
|
-
|
|
18934
|
-
if (!texture) {
|
|
18935
|
-
throw new Error(`Texture ${id} not found in atlas. Have you called toodle.loadTextures with this id or toodle.loadBundle with a bundle that contains it?`);
|
|
18936
|
-
}
|
|
18937
|
-
return texture[0].cropOffset;
|
|
19121
|
+
return this.bundles.getTextureOffset(id);
|
|
18938
19122
|
},
|
|
18939
19123
|
getAtlasUsage: () => {
|
|
18940
19124
|
return {
|
|
@@ -18971,25 +19155,13 @@ class AssetManager {
|
|
|
18971
19155
|
}, [atlas.texture.width, atlas.texture.height, 1]);
|
|
18972
19156
|
}
|
|
18973
19157
|
for (const [id, region] of atlas.textureRegions) {
|
|
18974
|
-
|
|
18975
|
-
if (existing) {
|
|
18976
|
-
existing.push({ ...region, atlasIndex });
|
|
18977
|
-
} else
|
|
18978
|
-
this.#addTexture(id, region, atlasIndex);
|
|
19158
|
+
this.bundles.addTextureEntry(id, { ...region, atlasIndex });
|
|
18979
19159
|
}
|
|
18980
19160
|
return atlasIndex;
|
|
18981
19161
|
},
|
|
18982
19162
|
unloadAtlas: async (atlasIndex) => {
|
|
18983
19163
|
this.#availableIndices.add(atlasIndex);
|
|
18984
|
-
|
|
18985
|
-
const indexToModify = coords.findIndex((coord) => coord.atlasIndex === atlasIndex);
|
|
18986
|
-
if (indexToModify !== -1) {
|
|
18987
|
-
coords.splice(indexToModify, 1);
|
|
18988
|
-
}
|
|
18989
|
-
if (!coords.length) {
|
|
18990
|
-
this.#textures.delete(id);
|
|
18991
|
-
}
|
|
18992
|
-
}
|
|
19164
|
+
this.bundles.removeTextureEntriesForAtlas(atlasIndex);
|
|
18993
19165
|
}
|
|
18994
19166
|
};
|
|
18995
19167
|
#wrapBitmapToTexture(bitmap, name = "Unknown") {
|
|
@@ -19230,7 +19402,7 @@ class Toodle {
|
|
|
19230
19402
|
}
|
|
19231
19403
|
Quad(assetId, options = {}) {
|
|
19232
19404
|
const assetManager = options.assetManager ?? this.assets;
|
|
19233
|
-
options.
|
|
19405
|
+
options.size ??= assetManager.getSize(assetId);
|
|
19234
19406
|
options.shader ??= this.#defaultQuadShader();
|
|
19235
19407
|
options.atlasCoords ??= assetManager.extra.getAtlasCoords(assetId)[0];
|
|
19236
19408
|
options.textureId ??= assetId;
|
|
@@ -19279,7 +19451,7 @@ class Toodle {
|
|
|
19279
19451
|
width: originalSize.width,
|
|
19280
19452
|
height: originalSize.height
|
|
19281
19453
|
};
|
|
19282
|
-
options.
|
|
19454
|
+
options.size ??= {
|
|
19283
19455
|
width: originalSize.width,
|
|
19284
19456
|
height: originalSize.height
|
|
19285
19457
|
};
|
|
@@ -19296,7 +19468,7 @@ class Toodle {
|
|
|
19296
19468
|
}
|
|
19297
19469
|
shapes = {
|
|
19298
19470
|
Rect: (options = {}) => {
|
|
19299
|
-
options.
|
|
19471
|
+
options.size ??= { width: 1, height: 1 };
|
|
19300
19472
|
options.shader ??= this.#defaultQuadShader();
|
|
19301
19473
|
options.atlasCoords ??= {
|
|
19302
19474
|
atlasIndex: 1000,
|
|
@@ -19318,18 +19490,23 @@ class Toodle {
|
|
|
19318
19490
|
}
|
|
19319
19491
|
return quad;
|
|
19320
19492
|
},
|
|
19321
|
-
Circle: (options = {}) => {
|
|
19322
|
-
|
|
19323
|
-
|
|
19324
|
-
|
|
19325
|
-
|
|
19326
|
-
|
|
19327
|
-
|
|
19328
|
-
|
|
19329
|
-
|
|
19493
|
+
Circle: (options = { radius: 50 }) => {
|
|
19494
|
+
const radius = options.radius ?? 50;
|
|
19495
|
+
const diameter = radius * 2;
|
|
19496
|
+
const quadOptions = {
|
|
19497
|
+
...options,
|
|
19498
|
+
size: { width: diameter, height: diameter },
|
|
19499
|
+
shader: options.shader ?? this.#defaultQuadShader(),
|
|
19500
|
+
atlasCoords: options.atlasCoords ?? {
|
|
19501
|
+
atlasIndex: 1001,
|
|
19502
|
+
uvOffset: { x: 0, y: 0 },
|
|
19503
|
+
uvScale: { width: 0, height: 0 },
|
|
19504
|
+
cropOffset: { x: 0, y: 0 },
|
|
19505
|
+
originalSize: { width: 1, height: 1 }
|
|
19506
|
+
},
|
|
19507
|
+
assetManager: this.assets
|
|
19330
19508
|
};
|
|
19331
|
-
|
|
19332
|
-
const quad = new QuadNode(options, this.#matrixPool);
|
|
19509
|
+
const quad = new QuadNode(quadOptions, this.#matrixPool);
|
|
19333
19510
|
if (options?.position) {
|
|
19334
19511
|
quad.position = options.position;
|
|
19335
19512
|
}
|
|
@@ -19358,7 +19535,7 @@ class Toodle {
|
|
|
19358
19535
|
originalSize: { width: 1, height: 1 }
|
|
19359
19536
|
},
|
|
19360
19537
|
shader: options.shader ?? this.#defaultQuadShader(),
|
|
19361
|
-
|
|
19538
|
+
size: { width: 1, height: 1 },
|
|
19362
19539
|
layer: options.layer,
|
|
19363
19540
|
key: options.key,
|
|
19364
19541
|
rotationRadians: angle,
|
|
@@ -19647,6 +19824,9 @@ __export(exports_mod7, {
|
|
|
19647
19824
|
});
|
|
19648
19825
|
// src/textures/mod.ts
|
|
19649
19826
|
var exports_mod8 = {};
|
|
19827
|
+
__export(exports_mod8, {
|
|
19828
|
+
Bundles: () => Bundles
|
|
19829
|
+
});
|
|
19650
19830
|
export {
|
|
19651
19831
|
exports_mod as Utils,
|
|
19652
19832
|
Toodle,
|
|
@@ -19658,8 +19838,9 @@ export {
|
|
|
19658
19838
|
exports_mod3 as GfxMath,
|
|
19659
19839
|
DEFAULT_LIMITS,
|
|
19660
19840
|
exports_mod2 as Colors,
|
|
19841
|
+
Bundles,
|
|
19661
19842
|
AssetManager
|
|
19662
19843
|
};
|
|
19663
19844
|
|
|
19664
|
-
//# debugId=
|
|
19845
|
+
//# debugId=70898D8E4A9F02C164756E2164756E21
|
|
19665
19846
|
//# sourceMappingURL=mod.js.map
|