@bloopjs/toodle 0.0.101 → 0.0.103
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 +1 -0
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +307 -132
- package/dist/mod.js.map +5 -4
- 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/package.json +1 -1
- package/src/mod.ts +1 -0
- package/src/textures/AssetManager.ts +42 -194
- package/src/textures/Bundles.ts +541 -0
- package/src/textures/mod.ts +2 -0
|
@@ -4,14 +4,22 @@ import type { Limits } from "../limits";
|
|
|
4
4
|
import { QuadNode } from "../scene/QuadNode";
|
|
5
5
|
import type { SceneNode } from "../scene/SceneNode";
|
|
6
6
|
import { TextShader } from "../text/TextShader";
|
|
7
|
+
import { Bundles } from "./Bundles";
|
|
7
8
|
import type { AtlasBundleOpts, AtlasCoords, CpuTextureAtlas, TextureBundleOpts } from "./types";
|
|
8
9
|
export type TextureId = string;
|
|
9
10
|
export type BundleId = string;
|
|
10
11
|
export type FontId = string;
|
|
12
|
+
export type AssetManagerOptions = {
|
|
13
|
+
/** Existing Bundles instance to use for CPU-side storage. If not provided, a new one is created. */
|
|
14
|
+
bundles?: Bundles;
|
|
15
|
+
/** Texture format (default: "rgba8unorm") */
|
|
16
|
+
format?: "rgba8unorm" | "rg8unorm";
|
|
17
|
+
};
|
|
11
18
|
export declare class AssetManager {
|
|
12
19
|
#private;
|
|
13
20
|
readonly textureAtlas: GPUTexture;
|
|
14
|
-
|
|
21
|
+
readonly bundles: Bundles;
|
|
22
|
+
constructor(device: GPUDevice, presentationFormat: GPUTextureFormat, limits: Limits, options?: AssetManagerOptions);
|
|
15
23
|
/**
|
|
16
24
|
* True dimensions of a loaded texture, prior to any transparent pixel cropping.
|
|
17
25
|
*
|
|
@@ -36,7 +44,7 @@ export declare class AssetManager {
|
|
|
36
44
|
/**
|
|
37
45
|
* A read-only map of all currently loaded textures.
|
|
38
46
|
*/
|
|
39
|
-
get textures():
|
|
47
|
+
get textures(): ReadonlyMap<string, AtlasCoords[]>;
|
|
40
48
|
/**
|
|
41
49
|
* A read-only array of all currently loaded texture ids.
|
|
42
50
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssetManager.d.ts","sourceRoot":"","sources":["../../src/textures/AssetManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGpD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"AssetManager.d.ts","sourceRoot":"","sources":["../../src/textures/AssetManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGpD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,eAAe,EACf,iBAAiB,EAElB,MAAM,SAAS,CAAC;AAGjB,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAC/B,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAC9B,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC;AAE5B,MAAM,MAAM,mBAAmB,GAAG;IAChC,oGAAoG;IACpG,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;CACpC,CAAC;AAEF,qBAAa,YAAY;;IACvB,QAAQ,CAAC,YAAY,EAAE,UAAU,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;gBASxB,MAAM,EAAE,SAAS,EACjB,kBAAkB,EAAE,gBAAgB,EACpC,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,mBAAwB;IA2BnC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI;IAS5B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI;IAWnC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO;IAUjC;;OAEG;IACH,IAAI,QAAQ,uCAEX;IAED;;OAEG;IACH,IAAI,UAAU,aAEb;IAED;;;;;;;;;;;;;;;;OAgBG;IACG,YAAY,CAAC,IAAI,EAAE,iBAAiB,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAMtE;;;;;;;;;OASG;IACG,WAAW,CACf,EAAE,EAAE,SAAS,EACb,GAAG,EAAE,GAAG,GAAG,WAAW,EACtB,OAAO,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC;;;;IAwCtC;;;;;;;;OAQG;IACG,cAAc,CAClB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,iBAAiB,GAAG,eAAe,GACxC,OAAO,CAAC,QAAQ,CAAC;IAapB;;;;OAIG;IACG,UAAU,CAAC,QAAQ,EAAE,QAAQ;IAsBnC;;;;;OAKG;IACG,YAAY,CAAC,QAAQ,EAAE,QAAQ;IAkBrC;;;;;;OAMG;IACG,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB,SAAM;IAqB5D,OAAO,CAAC,EAAE,EAAE,MAAM;IASlB,wBAAwB,CAAC,IAAI,EAAE,SAAS,GAAG,QAAQ;IA4FnD;;OAEG;IACH,KAAK;sCAEyB,MAAM,EAAE;kCAKZ,MAAM,EAAE;QAIhC;;;;;;;WAOG;6BACkB,SAAS,UAAU,WAAW;QAInD;;;;;WAKG;6BACkB,SAAS,KAAG,WAAW,EAAE;QAI9C;;;;;WAKG;+BACoB,SAAS,KAAG,IAAI;QAIvC;;;;WAIG;;YAGC;;;eAGG;;YAEH;;eAEG;;YAEH;;eAEG;;;QAKP;;;WAGG;;QAWH;;;;;WAKG;2BACsB,eAAe;QAsCxC;;;;WAIG;kCAC6B,MAAM;MAItC;IAmCF;;OAEG;IACH,OAAO;CAGR"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundles - A renderer-agnostic class for managing texture bundles and atlas coordinates.
|
|
3
|
+
*
|
|
4
|
+
* This class can be used standalone (without WebGPU) for:
|
|
5
|
+
* - Registering pre-baked texture atlases (Pixi/AssetPack format)
|
|
6
|
+
* - Looking up texture regions and UV coordinates
|
|
7
|
+
* - Managing bundle state
|
|
8
|
+
*
|
|
9
|
+
* For WebGPU rendering, use AssetManager which wraps this class and handles GPU operations.
|
|
10
|
+
*/
|
|
11
|
+
import type { Size } from "../coreTypes/Size";
|
|
12
|
+
import type { Vec2 } from "../coreTypes/Vec2";
|
|
13
|
+
import type { AtlasBundleOpts, AtlasCoords, CpuTextureAtlas, TextureRegion } from "./types";
|
|
14
|
+
export type TextureId = string;
|
|
15
|
+
export type BundleId = string;
|
|
16
|
+
/**
|
|
17
|
+
* Options for creating a Bundles instance
|
|
18
|
+
*/
|
|
19
|
+
export type BundlesOptions = {
|
|
20
|
+
/** The size of the texture atlas (default: 4096) */
|
|
21
|
+
atlasSize?: number;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Bundles manages texture bundle registration and atlas coordinate lookups.
|
|
25
|
+
*
|
|
26
|
+
* This is a pure TypeScript class with no WebGPU dependencies, suitable for
|
|
27
|
+
* use with custom renderers (e.g., WebGL fallbacks).
|
|
28
|
+
*/
|
|
29
|
+
export declare class Bundles {
|
|
30
|
+
#private;
|
|
31
|
+
constructor(options?: BundlesOptions);
|
|
32
|
+
/**
|
|
33
|
+
* Register a bundle of pre-baked texture atlases.
|
|
34
|
+
*
|
|
35
|
+
* @param bundleId - Unique identifier for this bundle
|
|
36
|
+
* @param opts - Atlas bundle options containing atlas definitions
|
|
37
|
+
* @returns The bundle ID
|
|
38
|
+
*/
|
|
39
|
+
registerAtlasBundle(bundleId: BundleId, opts: AtlasBundleOpts): Promise<BundleId>;
|
|
40
|
+
/**
|
|
41
|
+
* Register a bundle with pre-built CPU texture atlases.
|
|
42
|
+
* Used internally by AssetManager for texture bundles that require GPU packing.
|
|
43
|
+
*
|
|
44
|
+
* @param bundleId - Unique identifier for this bundle
|
|
45
|
+
* @param atlases - Pre-built CPU texture atlases
|
|
46
|
+
*/
|
|
47
|
+
registerDynamicBundle(bundleId: BundleId, atlases: CpuTextureAtlas[]): void;
|
|
48
|
+
/**
|
|
49
|
+
* Check if a bundle is registered.
|
|
50
|
+
*
|
|
51
|
+
* @param bundleId - The bundle ID to check
|
|
52
|
+
*/
|
|
53
|
+
hasBundle(bundleId: BundleId): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Check if a bundle is loaded.
|
|
56
|
+
*
|
|
57
|
+
* @param bundleId - The bundle ID to check
|
|
58
|
+
*/
|
|
59
|
+
isBundleLoaded(bundleId: BundleId): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Get the atlas indices for a loaded bundle.
|
|
62
|
+
*
|
|
63
|
+
* @param bundleId - The bundle ID
|
|
64
|
+
* @returns Array of atlas indices, or empty array if not loaded
|
|
65
|
+
*/
|
|
66
|
+
getBundleAtlasIndices(bundleId: BundleId): number[];
|
|
67
|
+
/**
|
|
68
|
+
* Mark a bundle as loaded without populating texture lookups.
|
|
69
|
+
* Used when texture lookups are already populated via loadAtlas.
|
|
70
|
+
*
|
|
71
|
+
* @param bundleId - The bundle to mark as loaded
|
|
72
|
+
* @param atlasIndices - Array of atlas indices, one per atlas
|
|
73
|
+
*/
|
|
74
|
+
setBundleLoaded(bundleId: BundleId, atlasIndices: number[]): void;
|
|
75
|
+
/**
|
|
76
|
+
* Mark a bundle as loaded and populate texture lookups.
|
|
77
|
+
* For standalone usage (without AssetManager).
|
|
78
|
+
*
|
|
79
|
+
* @param bundleId - The bundle to mark as loaded
|
|
80
|
+
* @param atlasIndices - Array of atlas indices, one per atlas. If not provided, indices are auto-assigned sequentially.
|
|
81
|
+
*/
|
|
82
|
+
markBundleLoaded(bundleId: BundleId, atlasIndices?: number[]): void;
|
|
83
|
+
/**
|
|
84
|
+
* Unmark a bundle as loaded and remove texture lookups.
|
|
85
|
+
*
|
|
86
|
+
* @param bundleId - The bundle to unload
|
|
87
|
+
*/
|
|
88
|
+
unloadBundle(bundleId: BundleId): void;
|
|
89
|
+
/**
|
|
90
|
+
* A read-only map of all currently loaded textures.
|
|
91
|
+
*/
|
|
92
|
+
get textures(): ReadonlyMap<TextureId, AtlasCoords[]>;
|
|
93
|
+
/**
|
|
94
|
+
* A read-only array of all currently loaded texture ids.
|
|
95
|
+
*/
|
|
96
|
+
get textureIds(): TextureId[];
|
|
97
|
+
/**
|
|
98
|
+
* Get the atlas coordinates for a texture.
|
|
99
|
+
*
|
|
100
|
+
* @param id - The texture ID
|
|
101
|
+
* @returns Array of atlas coordinates (may have multiple if texture exists in multiple atlases)
|
|
102
|
+
*/
|
|
103
|
+
getAtlasCoords(id: TextureId): AtlasCoords[];
|
|
104
|
+
/**
|
|
105
|
+
* Set the atlas coordinates for a texture.
|
|
106
|
+
* This allows for UV precision adjustments.
|
|
107
|
+
*
|
|
108
|
+
* @param id - The texture ID
|
|
109
|
+
* @param coords - The atlas coordinates to set
|
|
110
|
+
*/
|
|
111
|
+
setAtlasCoords(id: TextureId, coords: AtlasCoords): void;
|
|
112
|
+
/**
|
|
113
|
+
* Add atlas coordinates for a texture entry.
|
|
114
|
+
* Used by AssetManager.loadAtlas for textures loaded outside of bundles.
|
|
115
|
+
*
|
|
116
|
+
* @param id - The texture ID
|
|
117
|
+
* @param coords - The atlas coordinates to add
|
|
118
|
+
*/
|
|
119
|
+
addTextureEntry(id: TextureId, coords: AtlasCoords): void;
|
|
120
|
+
/**
|
|
121
|
+
* Remove texture entries for a specific atlas index.
|
|
122
|
+
* Used by AssetManager.unloadAtlas.
|
|
123
|
+
*
|
|
124
|
+
* @param atlasIndex - The atlas index to remove entries for
|
|
125
|
+
*/
|
|
126
|
+
removeTextureEntriesForAtlas(atlasIndex: number): void;
|
|
127
|
+
/**
|
|
128
|
+
* Get the texture region (without atlas index) for a texture.
|
|
129
|
+
*
|
|
130
|
+
* @param id - The texture ID
|
|
131
|
+
* @returns The texture region, or undefined if not found
|
|
132
|
+
*/
|
|
133
|
+
getTextureRegion(id: TextureId): TextureRegion | undefined;
|
|
134
|
+
/**
|
|
135
|
+
* Get the crop offset for a texture.
|
|
136
|
+
*
|
|
137
|
+
* @param id - The texture ID
|
|
138
|
+
* @returns The crop offset vector
|
|
139
|
+
*/
|
|
140
|
+
getTextureOffset(id: TextureId): Vec2;
|
|
141
|
+
/**
|
|
142
|
+
* Get the original (uncropped) size of a texture.
|
|
143
|
+
*
|
|
144
|
+
* @param id - The texture ID
|
|
145
|
+
* @returns The original size in pixels
|
|
146
|
+
*/
|
|
147
|
+
getSize(id: TextureId): Size;
|
|
148
|
+
/**
|
|
149
|
+
* Get the cropped size of a texture.
|
|
150
|
+
*
|
|
151
|
+
* @param id - The texture ID
|
|
152
|
+
* @returns The cropped size in pixels
|
|
153
|
+
*/
|
|
154
|
+
getCroppedSize(id: TextureId): Size;
|
|
155
|
+
/**
|
|
156
|
+
* Check if a texture exists.
|
|
157
|
+
*
|
|
158
|
+
* @param id - The texture ID
|
|
159
|
+
* @returns True if the texture is registered
|
|
160
|
+
*/
|
|
161
|
+
hasTexture(id: TextureId): boolean;
|
|
162
|
+
/**
|
|
163
|
+
* Get all registered bundle IDs.
|
|
164
|
+
*/
|
|
165
|
+
getRegisteredBundleIds(): BundleId[];
|
|
166
|
+
/**
|
|
167
|
+
* Get all loaded bundle IDs.
|
|
168
|
+
*/
|
|
169
|
+
getLoadedBundleIds(): BundleId[];
|
|
170
|
+
/**
|
|
171
|
+
* Get the CPU-side atlas data for a bundle.
|
|
172
|
+
* Useful for custom renderers that need access to the raw atlas data.
|
|
173
|
+
*
|
|
174
|
+
* @param bundleId - The bundle ID
|
|
175
|
+
* @returns Array of CPU texture atlases
|
|
176
|
+
*/
|
|
177
|
+
getBundleAtlases(bundleId: BundleId): CpuTextureAtlas[];
|
|
178
|
+
/**
|
|
179
|
+
* The atlas size used for coordinate calculations.
|
|
180
|
+
*/
|
|
181
|
+
get atlasSize(): number;
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=Bundles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Bundles.d.ts","sourceRoot":"","sources":["../../src/textures/Bundles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,eAAe,EAEf,aAAa,EACd,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAC/B,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAQ9B;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,OAAO;;gBAKN,OAAO,GAAE,cAAmB;IAIxC;;;;;;OAMG;IACG,mBAAmB,CACvB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,QAAQ,CAAC;IAmEpB;;;;;;OAMG;IACH,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI;IAQ3E;;;;OAIG;IACH,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO;IAItC;;;;OAIG;IACH,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO;IAK3C;;;;;OAKG;IACH,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,EAAE;IAKnD;;;;;;OAMG;IACH,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI;IASjE;;;;;;OAMG;IACH,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI;IAwCnE;;;;OAIG;IACH,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IA8BtC;;OAEG;IACH,IAAI,QAAQ,IAAI,WAAW,CAAC,SAAS,EAAE,WAAW,EAAE,CAAC,CAEpD;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,SAAS,EAAE,CAE5B;IAED;;;;;OAKG;IACH,cAAc,CAAC,EAAE,EAAE,SAAS,GAAG,WAAW,EAAE;IAU5C;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI;IAWxD;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI;IASzD;;;;;OAKG;IACH,4BAA4B,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IActD;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,EAAE,SAAS,GAAG,aAAa,GAAG,SAAS;IAQ1D;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI;IAUrC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI;IAS5B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI;IAYnC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO;IAIlC;;OAEG;IACH,sBAAsB,IAAI,QAAQ,EAAE;IAIpC;;OAEG;IACH,kBAAkB,IAAI,QAAQ,EAAE;IAMhC;;;;;;OAMG;IACH,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,GAAG,eAAe,EAAE;IAQvD;;OAEG;IACH,IAAI,SAAS,IAAI,MAAM,CAEtB;CA0EF"}
|
package/dist/textures/mod.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/textures/mod.ts"],"names":[],"mappings":"AAAA,mBAAmB,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/textures/mod.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,mBAAmB,SAAS,CAAC"}
|
package/package.json
CHANGED
package/src/mod.ts
CHANGED
|
@@ -8,14 +8,13 @@ import { FontPipeline } from "../text/FontPipeline";
|
|
|
8
8
|
import { MsdfFont } from "../text/MsdfFont";
|
|
9
9
|
import { TextShader } from "../text/TextShader";
|
|
10
10
|
import { assert } from "../utils/mod";
|
|
11
|
+
import { Bundles } from "./Bundles";
|
|
11
12
|
import { TextureComputeShader } from "./TextureComputeShader";
|
|
12
13
|
import type {
|
|
13
14
|
AtlasBundleOpts,
|
|
14
15
|
AtlasCoords,
|
|
15
16
|
CpuTextureAtlas,
|
|
16
|
-
PixiRegion,
|
|
17
17
|
TextureBundleOpts,
|
|
18
|
-
TextureRegion,
|
|
19
18
|
TextureWithMetadata,
|
|
20
19
|
} from "./types";
|
|
21
20
|
import { getBitmapFromUrl, packBitmapsToAtlas } from "./util";
|
|
@@ -24,18 +23,18 @@ export type TextureId = string;
|
|
|
24
23
|
export type BundleId = string;
|
|
25
24
|
export type FontId = string;
|
|
26
25
|
|
|
27
|
-
type
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
export type AssetManagerOptions = {
|
|
27
|
+
/** Existing Bundles instance to use for CPU-side storage. If not provided, a new one is created. */
|
|
28
|
+
bundles?: Bundles;
|
|
29
|
+
/** Texture format (default: "rgba8unorm") */
|
|
30
|
+
format?: "rgba8unorm" | "rg8unorm";
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
export class AssetManager {
|
|
34
34
|
readonly textureAtlas: GPUTexture;
|
|
35
|
+
readonly bundles: Bundles;
|
|
35
36
|
#device: GPUDevice;
|
|
36
37
|
#presentationFormat: GPUTextureFormat;
|
|
37
|
-
#bundles: Map<BundleId, Bundle> = new Map();
|
|
38
|
-
#textures: Map<string, AtlasCoords[]> = new Map();
|
|
39
38
|
#fonts: Map<string, TextShader> = new Map();
|
|
40
39
|
#cropComputeShader: TextureComputeShader;
|
|
41
40
|
#limits: Limits;
|
|
@@ -45,11 +44,14 @@ export class AssetManager {
|
|
|
45
44
|
device: GPUDevice,
|
|
46
45
|
presentationFormat: GPUTextureFormat,
|
|
47
46
|
limits: Limits,
|
|
48
|
-
|
|
47
|
+
options: AssetManagerOptions = {},
|
|
49
48
|
) {
|
|
50
49
|
this.#device = device;
|
|
51
50
|
this.#presentationFormat = presentationFormat;
|
|
52
51
|
this.#limits = limits;
|
|
52
|
+
this.bundles =
|
|
53
|
+
options.bundles ?? new Bundles({ atlasSize: limits.textureSize });
|
|
54
|
+
const format = options.format ?? "rgba8unorm";
|
|
53
55
|
this.textureAtlas = device.createTexture({
|
|
54
56
|
label: "Asset Manager Atlas Texture",
|
|
55
57
|
size: [
|
|
@@ -108,27 +110,27 @@ export class AssetManager {
|
|
|
108
110
|
* @returns Whether the image has been cropped (i.e. if it has uvScaledCropped)
|
|
109
111
|
*/
|
|
110
112
|
isCropped(id: TextureId): boolean {
|
|
111
|
-
if (!this
|
|
113
|
+
if (!this.bundles.hasTexture(id)) {
|
|
112
114
|
throw new Error(
|
|
113
115
|
`Texture ${id} not found in atlas. Have you called toodle.loadTextures with this id or toodle.loadBundle with a bundle that contains it?`,
|
|
114
116
|
);
|
|
115
117
|
}
|
|
116
118
|
|
|
117
|
-
return this
|
|
119
|
+
return this.bundles.getAtlasCoords(id)[0].uvScaleCropped === undefined;
|
|
118
120
|
}
|
|
119
121
|
|
|
120
122
|
/**
|
|
121
123
|
* A read-only map of all currently loaded textures.
|
|
122
124
|
*/
|
|
123
125
|
get textures() {
|
|
124
|
-
return this
|
|
126
|
+
return this.bundles.textures;
|
|
125
127
|
}
|
|
126
128
|
|
|
127
129
|
/**
|
|
128
130
|
* A read-only array of all currently loaded texture ids.
|
|
129
131
|
*/
|
|
130
132
|
get textureIds() {
|
|
131
|
-
return
|
|
133
|
+
return this.bundles.textureIds;
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
/**
|
|
@@ -200,7 +202,7 @@ export class AssetManager {
|
|
|
200
202
|
atlasIndex,
|
|
201
203
|
};
|
|
202
204
|
|
|
203
|
-
this
|
|
205
|
+
this.bundles.addTextureEntry(id, coords);
|
|
204
206
|
this.#availableIndices.delete(atlasIndex);
|
|
205
207
|
|
|
206
208
|
textureWrapper.texture.destroy();
|
|
@@ -238,22 +240,25 @@ export class AssetManager {
|
|
|
238
240
|
* See: https://toodle.gg/f849595b3ed13fc956fc1459a5cb5f0228f9d259/examples/texture-bundles.html
|
|
239
241
|
*/
|
|
240
242
|
async loadBundle(bundleId: BundleId) {
|
|
241
|
-
|
|
242
|
-
if (!bundle) {
|
|
243
|
+
if (!this.bundles.hasBundle(bundleId)) {
|
|
243
244
|
throw new Error(`Bundle ${bundleId} not found`);
|
|
244
245
|
}
|
|
245
246
|
|
|
246
|
-
if (
|
|
247
|
+
if (this.bundles.isBundleLoaded(bundleId)) {
|
|
247
248
|
console.warn(`Bundle ${bundleId} is already loaded.`);
|
|
248
249
|
return;
|
|
249
250
|
}
|
|
250
251
|
|
|
251
|
-
|
|
252
|
+
const atlases = this.bundles.getBundleAtlases(bundleId);
|
|
253
|
+
const atlasIndices: number[] = [];
|
|
254
|
+
|
|
255
|
+
for (const atlas of atlases) {
|
|
252
256
|
const atlasIndex = await this.extra.loadAtlas(atlas);
|
|
253
|
-
|
|
257
|
+
atlasIndices.push(atlasIndex);
|
|
254
258
|
}
|
|
255
259
|
|
|
256
|
-
|
|
260
|
+
// Use setBundleLoaded (not markBundleLoaded) since loadAtlas already populated textures
|
|
261
|
+
this.bundles.setBundleLoaded(bundleId, atlasIndices);
|
|
257
262
|
}
|
|
258
263
|
|
|
259
264
|
/**
|
|
@@ -263,24 +268,21 @@ export class AssetManager {
|
|
|
263
268
|
* @param bundleId - The id of the bundle to unload
|
|
264
269
|
*/
|
|
265
270
|
async unloadBundle(bundleId: BundleId) {
|
|
266
|
-
|
|
267
|
-
if (!bundle) {
|
|
271
|
+
if (!this.bundles.hasBundle(bundleId)) {
|
|
268
272
|
throw new Error(`Bundle ${bundleId} not found`);
|
|
269
273
|
}
|
|
270
274
|
|
|
271
|
-
if (!
|
|
275
|
+
if (!this.bundles.isBundleLoaded(bundleId)) {
|
|
272
276
|
console.warn(`Bundle ${bundleId} is not loaded.`);
|
|
273
277
|
return;
|
|
274
278
|
}
|
|
275
279
|
|
|
280
|
+
const atlasIndices = this.bundles.getBundleAtlasIndices(bundleId);
|
|
276
281
|
await Promise.all(
|
|
277
|
-
|
|
278
|
-
this.extra.unloadAtlas(atlasIndex),
|
|
279
|
-
),
|
|
282
|
+
atlasIndices.map((atlasIndex) => this.extra.unloadAtlas(atlasIndex)),
|
|
280
283
|
);
|
|
281
284
|
|
|
282
|
-
|
|
283
|
-
bundle.atlasIndices = [];
|
|
285
|
+
this.bundles.unloadBundle(bundleId);
|
|
284
286
|
}
|
|
285
287
|
|
|
286
288
|
/**
|
|
@@ -328,15 +330,13 @@ export class AssetManager {
|
|
|
328
330
|
)
|
|
329
331
|
return;
|
|
330
332
|
|
|
331
|
-
|
|
332
|
-
node.textureId,
|
|
333
|
-
);
|
|
334
|
-
if (!coords || !coords.length) {
|
|
333
|
+
if (!this.bundles.hasTexture(node.textureId)) {
|
|
335
334
|
throw new Error(
|
|
336
335
|
`Node ${node.id} references an invalid texture ${node.textureId}.`,
|
|
337
336
|
);
|
|
338
337
|
}
|
|
339
338
|
|
|
339
|
+
const coords = this.bundles.getAtlasCoords(node.textureId);
|
|
340
340
|
if (
|
|
341
341
|
coords.find((coord) => coord.atlasIndex === node.atlasCoords.atlasIndex)
|
|
342
342
|
)
|
|
@@ -345,22 +345,6 @@ export class AssetManager {
|
|
|
345
345
|
node.extra.setAtlasCoords(coords[0]);
|
|
346
346
|
}
|
|
347
347
|
|
|
348
|
-
/**
|
|
349
|
-
* Sets a designated texture ID to the corresponding `AtlasRegion` built from a `TextureRegion` and `numerical atlas index.
|
|
350
|
-
* @param id - `String` representing the texture name. I.e. "PlayerSprite"
|
|
351
|
-
* @param textureRegion - `TextureRegion` corresponding the uv and texture offsets
|
|
352
|
-
* @param atlasIndex - `number` of the atlas that the texture will live in.
|
|
353
|
-
* @private
|
|
354
|
-
*/
|
|
355
|
-
#addTexture(id: string, textureRegion: TextureRegion, atlasIndex: number) {
|
|
356
|
-
this.#textures.set(id, [
|
|
357
|
-
{
|
|
358
|
-
...textureRegion,
|
|
359
|
-
atlasIndex,
|
|
360
|
-
},
|
|
361
|
-
]);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
348
|
/**
|
|
365
349
|
*
|
|
366
350
|
* @param bitmap - `ImageBitmap` to be processed into a `GPUTexture` for storage and manipulation
|
|
@@ -422,115 +406,12 @@ export class AssetManager {
|
|
|
422
406
|
this.#device,
|
|
423
407
|
);
|
|
424
408
|
|
|
425
|
-
this
|
|
426
|
-
atlases,
|
|
427
|
-
atlasIndices: [],
|
|
428
|
-
isLoaded: false,
|
|
429
|
-
});
|
|
409
|
+
this.bundles.registerDynamicBundle(bundleId, atlases);
|
|
430
410
|
}
|
|
431
411
|
|
|
432
412
|
async #registerBundleFromAtlases(bundleId: BundleId, opts: AtlasBundleOpts) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
for (const atlas of opts.atlases) {
|
|
436
|
-
const jsonUrl =
|
|
437
|
-
atlas.json ??
|
|
438
|
-
new URL(
|
|
439
|
-
atlas.png!.toString().replace(".png", ".json"),
|
|
440
|
-
atlas.png!.origin,
|
|
441
|
-
);
|
|
442
|
-
const pngUrl =
|
|
443
|
-
atlas.png ??
|
|
444
|
-
new URL(
|
|
445
|
-
atlas.json!.toString().replace(".json", ".png"),
|
|
446
|
-
atlas.json!.origin,
|
|
447
|
-
);
|
|
448
|
-
|
|
449
|
-
const atlasDef = await (await fetch(jsonUrl)).json();
|
|
450
|
-
const bitmap = !opts.rg8
|
|
451
|
-
? await getBitmapFromUrl(pngUrl)
|
|
452
|
-
: await createImageBitmap(new ImageData(1, 1)); // placeholder bitmap if using rg8
|
|
453
|
-
|
|
454
|
-
let rg8Bytes: Uint8Array<ArrayBuffer> | undefined;
|
|
455
|
-
if (opts.rg8) {
|
|
456
|
-
const rg8url = new URL(
|
|
457
|
-
pngUrl.toString().replace(".png", ".rg8.gz"),
|
|
458
|
-
pngUrl.origin,
|
|
459
|
-
);
|
|
460
|
-
const rgBytes = await fetch(rg8url).then(async (r) => {
|
|
461
|
-
const enc = (r.headers.get("content-encoding") || "").toLowerCase();
|
|
462
|
-
// If server/CDN already set Content-Encoding, Fetch returns decompressed bytes.
|
|
463
|
-
if (
|
|
464
|
-
enc.includes("gzip") ||
|
|
465
|
-
enc.includes("br") ||
|
|
466
|
-
enc.includes("deflate")
|
|
467
|
-
) {
|
|
468
|
-
return new Uint8Array(await r.arrayBuffer());
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
assert(r.body, "Response body of rg8 file is null");
|
|
472
|
-
const ds = new DecompressionStream("gzip");
|
|
473
|
-
const ab = await new Response(r.body.pipeThrough(ds)).arrayBuffer();
|
|
474
|
-
return new Uint8Array(ab);
|
|
475
|
-
});
|
|
476
|
-
rg8Bytes = rgBytes;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
const cpuTextureAtlas: CpuTextureAtlas = {
|
|
480
|
-
texture: bitmap,
|
|
481
|
-
rg8Bytes,
|
|
482
|
-
textureRegions: new Map(),
|
|
483
|
-
width: opts.rg8 ? this.#limits.textureSize : bitmap.width,
|
|
484
|
-
height: opts.rg8 ? this.#limits.textureSize : bitmap.height,
|
|
485
|
-
};
|
|
486
|
-
|
|
487
|
-
for (const [assetId, frame] of Object.entries(atlasDef.frames) as [
|
|
488
|
-
string,
|
|
489
|
-
PixiRegion,
|
|
490
|
-
][]) {
|
|
491
|
-
const leftCrop = frame.spriteSourceSize.x;
|
|
492
|
-
const rightCrop =
|
|
493
|
-
frame.sourceSize.w -
|
|
494
|
-
frame.spriteSourceSize.x -
|
|
495
|
-
frame.spriteSourceSize.w;
|
|
496
|
-
const topCrop = frame.spriteSourceSize.y;
|
|
497
|
-
const bottomCrop =
|
|
498
|
-
frame.sourceSize.h -
|
|
499
|
-
frame.spriteSourceSize.y -
|
|
500
|
-
frame.spriteSourceSize.h;
|
|
501
|
-
|
|
502
|
-
cpuTextureAtlas.textureRegions.set(assetId, {
|
|
503
|
-
cropOffset: {
|
|
504
|
-
x: leftCrop - rightCrop,
|
|
505
|
-
y: bottomCrop - topCrop,
|
|
506
|
-
},
|
|
507
|
-
originalSize: {
|
|
508
|
-
width: frame.sourceSize.w,
|
|
509
|
-
height: frame.sourceSize.h,
|
|
510
|
-
},
|
|
511
|
-
uvOffset: {
|
|
512
|
-
x: frame.frame.x / cpuTextureAtlas.width,
|
|
513
|
-
y: frame.frame.y / cpuTextureAtlas.height,
|
|
514
|
-
},
|
|
515
|
-
uvScale: {
|
|
516
|
-
width: frame.sourceSize.w / cpuTextureAtlas.width,
|
|
517
|
-
height: frame.sourceSize.h / cpuTextureAtlas.height,
|
|
518
|
-
},
|
|
519
|
-
uvScaleCropped: {
|
|
520
|
-
width: frame.frame.w / cpuTextureAtlas.width,
|
|
521
|
-
height: frame.frame.h / cpuTextureAtlas.height,
|
|
522
|
-
},
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
atlases.push(cpuTextureAtlas);
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
this.#bundles.set(bundleId, {
|
|
530
|
-
atlases,
|
|
531
|
-
atlasIndices: [],
|
|
532
|
-
isLoaded: false,
|
|
533
|
-
});
|
|
413
|
+
// Delegate to the Bundles instance for atlas parsing
|
|
414
|
+
await this.bundles.registerAtlasBundle(bundleId, opts);
|
|
534
415
|
}
|
|
535
416
|
|
|
536
417
|
/**
|
|
@@ -539,14 +420,12 @@ export class AssetManager {
|
|
|
539
420
|
extra = {
|
|
540
421
|
// Get an array of all currently registered bundle ids.
|
|
541
422
|
getRegisteredBundleIds: (): string[] => {
|
|
542
|
-
return this
|
|
423
|
+
return this.bundles.getRegisteredBundleIds();
|
|
543
424
|
},
|
|
544
425
|
|
|
545
426
|
// Get an array of all currently loaded bundle ids.
|
|
546
427
|
getLoadedBundleIds: (): string[] => {
|
|
547
|
-
return
|
|
548
|
-
.filter(([, value]) => value.isLoaded)
|
|
549
|
-
.map(([key]) => key);
|
|
428
|
+
return this.bundles.getLoadedBundleIds();
|
|
550
429
|
},
|
|
551
430
|
|
|
552
431
|
/**
|
|
@@ -558,14 +437,7 @@ export class AssetManager {
|
|
|
558
437
|
* @param coords - The atlas coordinates to set
|
|
559
438
|
*/
|
|
560
439
|
setAtlasCoords: (id: TextureId, coords: AtlasCoords) => {
|
|
561
|
-
|
|
562
|
-
if (!oldCoords) return;
|
|
563
|
-
const indexToModify = oldCoords.findIndex(
|
|
564
|
-
(coord) => coord.atlasIndex === coords.atlasIndex,
|
|
565
|
-
);
|
|
566
|
-
if (indexToModify === -1) return;
|
|
567
|
-
oldCoords[indexToModify] = coords;
|
|
568
|
-
this.#textures.set(id, oldCoords);
|
|
440
|
+
this.bundles.setAtlasCoords(id, coords);
|
|
569
441
|
},
|
|
570
442
|
|
|
571
443
|
/**
|
|
@@ -575,12 +447,7 @@ export class AssetManager {
|
|
|
575
447
|
* @returns An array of the atlas coordinates for the texture
|
|
576
448
|
*/
|
|
577
449
|
getAtlasCoords: (id: TextureId): AtlasCoords[] => {
|
|
578
|
-
|
|
579
|
-
throw new Error(
|
|
580
|
-
`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)?`,
|
|
581
|
-
);
|
|
582
|
-
}
|
|
583
|
-
return this.#textures.get(id) ?? [];
|
|
450
|
+
return this.bundles.getAtlasCoords(id);
|
|
584
451
|
},
|
|
585
452
|
|
|
586
453
|
/**
|
|
@@ -590,13 +457,7 @@ export class AssetManager {
|
|
|
590
457
|
* @returns Point of the texture's associated X,Y offset
|
|
591
458
|
*/
|
|
592
459
|
getTextureOffset: (id: TextureId): Vec2 => {
|
|
593
|
-
|
|
594
|
-
if (!texture) {
|
|
595
|
-
throw new Error(
|
|
596
|
-
`Texture ${id} not found in atlas. Have you called toodle.loadTextures with this id or toodle.loadBundle with a bundle that contains it?`,
|
|
597
|
-
);
|
|
598
|
-
}
|
|
599
|
-
return texture[0].cropOffset;
|
|
460
|
+
return this.bundles.getTextureOffset(id);
|
|
600
461
|
},
|
|
601
462
|
|
|
602
463
|
/**
|
|
@@ -675,10 +536,7 @@ export class AssetManager {
|
|
|
675
536
|
}
|
|
676
537
|
|
|
677
538
|
for (const [id, region] of atlas.textureRegions) {
|
|
678
|
-
|
|
679
|
-
if (existing) {
|
|
680
|
-
existing.push({ ...region, atlasIndex });
|
|
681
|
-
} else this.#addTexture(id, region, atlasIndex);
|
|
539
|
+
this.bundles.addTextureEntry(id, { ...region, atlasIndex });
|
|
682
540
|
}
|
|
683
541
|
return atlasIndex;
|
|
684
542
|
},
|
|
@@ -690,17 +548,7 @@ export class AssetManager {
|
|
|
690
548
|
*/
|
|
691
549
|
unloadAtlas: async (atlasIndex: number) => {
|
|
692
550
|
this.#availableIndices.add(atlasIndex);
|
|
693
|
-
|
|
694
|
-
const indexToModify = coords.findIndex(
|
|
695
|
-
(coord) => coord.atlasIndex === atlasIndex,
|
|
696
|
-
);
|
|
697
|
-
if (indexToModify !== -1) {
|
|
698
|
-
coords.splice(indexToModify, 1);
|
|
699
|
-
}
|
|
700
|
-
if (!coords.length) {
|
|
701
|
-
this.#textures.delete(id);
|
|
702
|
-
}
|
|
703
|
-
}
|
|
551
|
+
this.bundles.removeTextureEntriesForAtlas(atlasIndex);
|
|
704
552
|
},
|
|
705
553
|
};
|
|
706
554
|
|