Texture Bundles
Loading textures can be surprisingly expensive. A 1024x1024 png may only be 100kb on disk, but when loaded into the gpu, each pixel is 4 bytes of rgba data, so that's 4mb of memory.
Bundles are a way to choose what is loaded into the gpu, to avoid hitting the VRAM memory limit (we recommend 4gb to cover lower-end devices).
ts
import { Toodle } from "@blooper.gg/toodle";
const canvas = document.querySelector("canvas")!;
const toodle = await Toodle.attach(canvas, {
filter: "nearest",
limits: { textureArrayLayers: 5 },
});
const produceTextures = {
ItemApple: new URL("img/ItemApple.png", "https://toodle.gg"),
ItemBanana: new URL("img/ItemBanana.png", "https://toodle.gg"),
ItemBroccoli: new URL("img/ItemBroccoli.png", "https://toodle.gg"),
ItemCherry: new URL("img/ItemCherry.png", "https://toodle.gg"),
ItemKiwi: new URL("img/ItemKiwi.png", "https://toodle.gg"),
ItemLemon: new URL("img/ItemLemon.png", "https://toodle.gg"),
ItemOnion: new URL("img/ItemOnion.png", "https://toodle.gg"),
ItemPea: new URL("img/ItemPea.png", "https://toodle.gg"),
ItemPeach: new URL("img/ItemPeach.png", "https://toodle.gg"),
ItemPumpkin: new URL("img/ItemPumpkin.png", "https://toodle.gg"),
ItemRadish: new URL("img/ItemRadish.png", "https://toodle.gg"),
ItemSpinach: new URL("img/ItemSpinach.png", "https://toodle.gg"),
ItemTomato: new URL("img/ItemTomato.png", "https://toodle.gg"),
};
const pantryTextures = {
ItemBaguette: new URL("img/ItemBaguette.png", "https://toodle.gg"),
ItemCheese: new URL("img/ItemCheese.png", "https://toodle.gg"),
ItemCoffee: new URL("img/ItemCoffee.png", "https://toodle.gg"),
ItemButterscotchCinnamonPie: new URL(
"img/ItemButterscotchCinnamonPie.png",
"https://toodle.gg",
),
ItemChilidog: new URL("img/ItemChilidog.png", "https://toodle.gg"),
ItemSeaSaltIceCream: new URL(
"img/ItemSeaSaltIceCream.png",
"https://toodle.gg",
),
ItemTurkeyLeg: new URL("img/ItemTurkeyLeg.png", "https://toodle.gg"),
};
await toodle.assets.registerBundle("produce", { textures: produceTextures });
await toodle.assets.registerBundle("pantry", { textures: pantryTextures });
await toodle.assets.loadBundle("produce");
await toodle.assets.loadBundle("pantry");
{
const usage = toodle.assets.extra.getAtlasUsage();
console.log("used", usage.used, "available", usage.available);
}
await toodle.assets.unloadBundle("pantry");
{
const usage = toodle.assets.extra.getAtlasUsage();
console.log("used", usage.used, "available", usage.available);
}
await toodle.assets.loadBundle("pantry");
toodle.startFrame();
toodle.draw(
toodle.Quad("ItemPumpkin", {
idealSize: { width: 100, height: 100 },
position: { x: -60, y: 0 },
}),
);
toodle.draw(
toodle.Quad("ItemTurkeyLeg", {
idealSize: { width: 100, height: 100 },
position: { x: 60, y: 0 },
}),
);
toodle.endFrame();
Duplicate Textures
Textures can be loaded into more than one bundle. You could have a character portrait on the main menu and character select screen, and both could be loaded into separate bundles at the same time.
ts
import { Toodle } from "@blooper.gg/toodle";
const canvas = document.querySelector("canvas")!;
const toodle = await Toodle.attach(canvas, {
filter: "nearest",
limits: { textureArrayLayers: 5 },
});
// Here we're going to get an Apple and some Spinach...
const produceTextures = {
ItemApple: new URL("img/ItemApple.png", "https://toodle.gg"),
ItemSpinach: new URL("img/ItemSpinach.png", "https://toodle.gg"),
};
// With our pantry textures holding SeaSaltIceCream and the same Spinach that can be found in our produce textures...
const pantryTextures = {
ItemSeaSaltIceCream: new URL(
"img/ItemSeaSaltIceCream.png",
"https://toodle.gg",
),
ItemSpinach: new URL("img/ItemSpinach.png", "https://toodle.gg"),
};
// A little extra ice cream in the freezer...
const freezerTextures = {
ItemSeaSaltIceCream: new URL(
"img/ItemSeaSaltIceCream.png",
"https://toodle.gg",
),
};
// Bundles are registered...
await toodle.assets.registerBundle("produce", { textures: produceTextures });
await toodle.assets.registerBundle("pantry", { textures: pantryTextures });
await toodle.assets.registerBundle("freezer", { textures: freezerTextures });
// and loaded...
await toodle.assets.loadBundle("produce");
await toodle.assets.loadBundle("pantry");
await toodle.assets.loadBundle("freezer");
// With the latter then being unloaded...
await toodle.assets.unloadBundle("pantry");
toodle.startFrame();
// But a draw call to `ItemSpinach` or `SeaSaltIceCream` will still work perfectly fine!
toodle.draw(
toodle.Quad("ItemSpinach", {
idealSize: { width: 100, height: 100 },
position: { x: -60, y: 0 },
}),
);
toodle.draw(
toodle.Quad("ItemSeaSaltIceCream", {
idealSize: { width: 100, height: 100 },
position: { x: 60, y: 0 },
}),
);
toodle.endFrame();