UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

164 lines (132 loc) 4.03 kB
import { LoadingCache } from "../../../../core/cache/LoadingCache.js"; import { strictEquals } from "../../../../core/function/strictEquals.js"; import { computeStringHash } from "../../../../core/primitives/strings/computeStringHash.js"; import { GameAssetType } from "../../../asset/GameAssetType.js"; import { Reference } from "../../../reference/v2/Reference.js"; import { Sampler2D } from "../sampler/Sampler2D.js"; import { sampler2d_ensure_uint8_RGBA } from "../sampler/sampler2d_ensure_uint8_RGBA.js"; import { CachingTextureAtlas } from "./CachingTextureAtlas.js"; import { TextureAtlas } from "./TextureAtlas.js"; export class ManagedAtlas { /** * * @type {AssetManager|null} */ #assets = null; /** * * @type {Map<string, Reference>} */ #references = new Map(); /** * Pixel padding * @type {number} */ #padding = 4; /** * @type {LoadingCache<string, AtlasPatch>} */ #patch_loader; /** * * @type {Map<string, AtlasPatch>} */ #url_patch_lookup = new Map(); /** * * @type {Map<AtlasPatch,string[]>} */ #patch_url_lookup = new Map(); /** * * @param {AssetManager} assetManager * @constructor */ constructor(assetManager) { this.#assets = assetManager; /** * pre-allocate space on the atlas to avoid some initial re-sizing * @type {TextureAtlas} */ const atlas = new TextureAtlas(64); this.__caching_atlas = new CachingTextureAtlas({ atlas }); /** * * @type {TextureAtlas} */ this.atlas = atlas; atlas.on.removed.add(this.#remove_from_lookup, this); this.#patch_loader = new LoadingCache({ keyHashFunction: computeStringHash, keyEqualityFunction: strictEquals, load: async (url) => { const sampler = await this.#resolve_texture(url); const patch = this.__caching_atlas.add(sampler, this.#padding); this.#add_to_lookup(url, patch); return patch; } }); } /** * * @param {AtlasPatch} patch */ #remove_from_lookup(patch) { const urls = this.#patch_url_lookup.get(patch); for (let i = 0; i < urls.length; i++) { const url = urls[i]; this.#url_patch_lookup.delete(url); } } /** * * @param {string} url * @param {AtlasPatch} patch */ #add_to_lookup(url, patch) { this.#url_patch_lookup.set(url, patch); let urls = this.#patch_url_lookup.get(patch); if (urls === undefined) { urls = []; this.#patch_url_lookup.set(patch, urls); } urls.push(url); } /** * * @param {string} url * @returns {Promise<Sampler2D>} */ async #resolve_texture(url) { const asset = await this.#assets.promise(url, GameAssetType.Image); const source = asset.create(); return sampler2d_ensure_uint8_RGBA(source); } reset() { this.#references.clear(); this.__caching_atlas.reset(); this.#url_patch_lookup.clear(); } /** * * @param {string} key * @returns {Promise<Reference<AtlasPatch>>} */ async acquire(url) { const reference = new Reference(); let patch = this.#url_patch_lookup.get(url); if (patch === undefined) { // patch is not active, need to load it patch = await this.#patch_loader.get(url); } reference.bind(patch); return reference; } /** * * @param {string} key */ release(key) { throw new Error('Method is deprecated, use "Reference.release" instead'); } }