UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

179 lines (145 loc) 4.92 kB
import { Cache } from "../../../../core/cache/Cache.js"; import { HashMap } from "../../../../core/collection/map/HashMap.js"; import { computeMaterialEquality } from "../../../asset/loaders/material/computeMaterialEquality.js"; import { computeMaterialHash } from "../../../asset/loaders/material/computeMaterialHash.js"; import { ManagedMaterial } from "./ManagedMaterial.js"; export class MaterialManager { constructor() { /** * Stores links from uncompiled (source) materials to managed containers * @type {HashMap<Material, ManagedMaterial>} * @private */ this.__library = new HashMap({ keyHashFunction: computeMaterialHash, keyEqualityFunction: computeMaterialEquality, capacity: 1024 }); /** * Cache for unused materials, gives them a second chance to be used before being disposed completely * @type {Cache<Material, ManagedMaterial>} * @private */ this.__cache = new Cache({ keyHashFunction: computeMaterialHash, keyEqualityFunction: computeMaterialEquality, maxWeight: 100 }); /** * Stores links from compiled materials back to the container * @type {HashMap<Material, ManagedMaterial>} * @private */ this.__reverse_library = new HashMap({ keyHashFunction: computeMaterialHash, keyEqualityFunction: computeMaterialEquality, capacity: 1024 }); this.__cache.onEvicted.add(this.__dispose_material, this); /** * * @type {AbstractMaterialTransformer[]} * @private */ this.__transform_chain = []; } /** * handle material disposal * @param {Material} m * @param {ManagedMaterial} managed_material * @private */ __dispose_material(m, managed_material) { managed_material.getMaterial().dispose(); } /** * * @param {ManagedMaterial} material * @private */ __handle_last_reference_removed(material) { const compiled_material = material.getMaterial(); // remove from library const source = material.getSource(); this.__library.delete(source); this.__reverse_library.delete(compiled_material); // put material into cache this.__cache.put(source, material); } /** * * @param {Function} klass * @return {AbstractMaterialTransformer[]} */ getCompilationSteps(klass){ return this.__transform_chain.filter(x => x instanceof klass); } /** * * @param {AbstractMaterialTransformer} def */ addCompileStep(def) { this.__transform_chain.push(def); } /** * * @param {AbstractMaterialTransformer} def * @returns {boolean} */ removeCompileStep(def) { const i = this.__transform_chain.indexOf(def); if (i === -1) { return false; } this.__transform_chain.splice(i, 1); return true; } /** * * @param {Material} m * @returns {Material} * @private */ __compile(m) { let r = m; const transformers = this.__transform_chain; const n = transformers.length; for (let i = 0; i < n; i++) { const transformer = transformers[i]; r = transformer.transform(r); } return r; } /** * * @param {Material} source * @returns {Reference<Material>} */ obtain(source) { // reverse check to see if this is actually an already compiled/managed material let material = this.__reverse_library.get(source); if (material !== undefined) { // already compiled material return material.getRef(); } // forward check material = this.__library.get(source); if (material === undefined) { // not found in library, check cache material = this.__cache.get(source); if (material !== null) { // remove from cache this.__cache.remove(source); } else { // material not found in cache const mat = this.__compile(source); material = new ManagedMaterial(mat); material.setSource(source); } material.onLastReleased.addOne(this.__handle_last_reference_removed, this); this.__library.set(source, material); this.__reverse_library.set(material.getMaterial(), material); } return material.getRef(); } }