registry_sprite_registry.js

import Sprite from "./sprite/sprite.js";
import Util from "../util/misc/util.js";
import Vec2 from "../game/vector/vec2.js";
import SpritePartition from "./sprite/sprite_partition.js";
import Bounds from "../game/vector/bounds.js";
import LayeredSprite from "./sprite/layered_sprite.js";

/**
 * @module SpriteRegistry
 * @fileoverview Contains SpriteRegistry class.
 */

/**
 * @class
 * Global registry for sprites.
 */
class SpriteRegistry {
    /**
     * Create a new sprite registry.
     * @constructor
     */
    constructor() {
        this._sprites = new Map();
        this._configs = new Map();

        this._wp = "";
    }

    /**
     * Set the working directory for importing sprites.
     * @param {string} p New working path
     */
    path(p) {
        const l = p.length - 1;
        if (p[l] !== '/' && p[l] !== '\\')
            p = p + "/";

        this._wp = p;
    }

    _processConfigs(sprite, configs) {
        let size = new Vec2(1, 1);

        if ("#size" in configs) {
            const val = configs["#size"];
            if (typeof val === "number")
                size = new Vec2(val, val);
            else if (val instanceof Vec2)
                size = val.copy();

            delete configs["#size"];
        }

        const result = {};

        for (const id of Object.keys(configs)) {
            const config = configs[id];
            if (config instanceof Array) {
                const from = new Vec2(config[0], config[1]);
                const to = from.addv(1, 1);
                result[id] = new SpritePartition({
                    sprite: sprite,
                    bounds: new Bounds(from.mul(size).floor(), to.mul(size).floor())
                })
            } else if ("from" in config && "to" in config) {
                const from = Vec2.from(config["from"]);
                const to = Vec2.from(config["to"]);
                result[id] = new SpritePartition({
                    sprite: sprite,
                    bounds: new Bounds(from.div(size).floor(), to.div(size).floor()),
                });
            } else if ("bounds" in config) {
                result[id] = new SpritePartition({
                    sprite: sprite,
                    bounds: config["bounds"]
                });
            }
        }

        return result;
    }

    /**
     * Add a new Sprite to the registry.
     * @param {string} id The unique ID of the Sprite
     * @param {string} src The image src of the Sprite
     * @param {Object.<string, Object>} configs Custom partition configurations
     * @param {number|null} width Default width of the Sprite (optional)
     * @param {number|null} height Default height of the Sprite (optional)
     */
    load(id, src, configs= {}, width = null, height = null) {
        $$.loadInc();

        Util.loadImage(this._wp + src, image => {
            if (width === null)
                width = image.width;
            if (height === null)
                height = image.height;

            const sprite= new Sprite(image, width, height);
            this._sprites.set(id, sprite);
            this._configs.set(id, this._processConfigs(sprite, configs));

            $$.loadDec();
        })
    }

    /**
     * Get a sprite with specified identifier.
     * @param {string} id Identifier of sprite
     * @returns {LayeredSprite|null} Sprite with specified identifier, or null if it does not exist.
     */
    get(id) {
        const sprites = [];

        for (const layer of id.split("/")) {
            const parts = layer.split(".");
            const partID = parts.splice(0, 1)[0];

            if (!this._sprites.has(partID))
                continue;

            if (parts[0] in this._configs.get(partID)) {
                sprites.push(this._configs.get(partID)[parts[0]].copy());
                continue;
            }

            sprites.push(new SpritePartition({
                sprite: this._sprites.get(partID)
            }));
        }

        if (sprites.length === 0)
            return null;

        return new LayeredSprite({
            sprites: sprites
        });
    }

    has(id) {
        return this._sprites.has(id);
    }
}

export default SpriteRegistry;