iwmlib/lib/pixi/deepzoom/tile.js

221 lines
6.1 KiB
JavaScript

const registeredTiles = new Map()
const pendingTiles = new Map()
/** Implements a baseTexture cache. The last textures are kept for reuse */
let keepTextures = 0
const keptTextures = []
/** The current Tile implementation simply uses PIXI.Sprites.
*
* BTW: PIXI.extras.TilingSprite is not appropriate. It should be used for
* repeating patterns.
**/
export default class Tile extends PIXI.Sprite {
constructor(texture, url) {
super(texture)
this.url = url
this.register(url)
}
/**
* Static method to enable keeping of base textures
*
* @static
* @param {*} value
* @memberof Tile
*/
static enableKeepTextures(value = 1000) {
keepTextures = value
}
/**
* Marks the given url as pending. Pending tiles should not be destroyed
*
* @static
* @param {*} url
* @memberof Tile
*/
static schedule(url) {
let count = 0
if (pendingTiles.has(url)) {
count = pendingTiles.get(url)
}
pendingTiles.set(url, count + 1)
// console.log("Tile.scheduled", url, pendingTiles.size)
}
/**
* Returns true iff the url is pending
*
* @static
* @param {*} url
* @returns
* @memberof Tile
*/
static isPending(url) {
return pendingTiles.has(url) && pendingTiles.get(url) > 0
}
static isObsolete(url) {
if (registeredTiles.has(url) && registeredTiles.get(url) > 0) {
return false
}
return true
}
/**
* Removes the given url from pending urls.
*
* @static
* @param {*} url
* @memberof Tile
*/
static unschedule(url) {
if (pendingTiles.has(url)) {
let count = pendingTiles.get(url)
if (count > 1) {
pendingTiles.set(url, count - 1)
}
else {
pendingTiles.clear(url)
}
}
// console.log("Tile.unscheduled", url, pendingTiles.size)
}
/**
* Loads a tile from image using the PIXI.Texture.fromImage method.
*
* @static
* @param {*} imageId
* @param {*} crossorigin
* @param {*} scaleMode
* @returns
* @memberof Tile
*/
static fromImage(imageId, crossorigin, scaleMode) {
return new Tile(PIXI.Texture.fromImage(imageId, crossorigin, scaleMode), imageId)
}
/**
* Registers the tile in the global reference counter for textures
*
* @param {*} url
* @param {boolean} [debug=false]
* @memberof Tile
*/
register(url, debug = false) {
Tile.unschedule(url)
if (registeredTiles.has(url)) {
let tiles = registeredTiles.get(url)
tiles.add(this)
if (debug) console.log("Tile.register", url, tiles.size)
}
else {
registeredTiles.set(url, new Set([this]))
if (debug) console.log("Tile.register", url, 1)
}
}
/**
* Unregisters the rile in the global reference counter for textures
*
* @returns {number} The number of how often a texture is used.
* @memberof Tile
*/
unregister() {
let tiles = registeredTiles.get(this.url)
tiles.delete(this)
if (tiles.size == 0) {
registeredTiles.delete(this.url)
return 0
}
return tiles.size
}
/**
* Destroys this sprite and optionally its texture and children
*
* @param {*} options Part of the PIXI API, but ignored in the implementation
* @memberof Tile
*/
destroy(options, debug = true) {
let count = this.unregister()
if (keepTextures > 0) {
keptTextures.push({ url: this.url, texture: this.texture})
let opts = { children: true, texture: false, baseTexture: false }
if (debug) console.log("Tile.destroy", registeredTiles.size, opts)
super.destroy(opts)
while(keptTextures.length > keepTextures) {
let {url, texture} = keptTextures.shift()
if (Tile.isObsolete(url)) {
texture.destroy(true) // Destroy base as well
if (debug) console.log("Destroying texture and baseTexture", url)
}
}
}
else {
// No longer registered and not pending
if (count <= 0 && !Tile.isPending(this.url)) {
let opts = { children: true, texture: true, baseTexture: true }
super.destroy(opts)
if (debug) console.log("Tile.destroy", registeredTiles.size, opts)
}
else {
let opts = { children: true, texture: false, baseTexture: false }
if (debug) console.log("Tile.destroy", registeredTiles.size, opts)
super.destroy(opts)
}
if (this.parent != null) {
// UO: Emit warning and remove
console.warn("Destroying tile with parent. Hiding instead")
this.visible = false
}
}
}
/**
* Returns an available texture that can be reused
*
* @param {*} url
* @returns
* @memberof Tile
*/
static textureAvailable(url) {
if (registeredTiles.has(url)) {
let tiles = registeredTiles.get(url)
for (let tile of tiles.values()) {
//console.log("Reusing cached texture", tile.parent)
return tile.texture
}
}
return null
}
/**
* Texture received too late. We do not need it.
* @param {*} url
* @param {*} texture
*/
static lateTexture(url, texture) {
let destroyBase = !registeredTiles.has(url)
texture.destroy(destroyBase)
}
static printInfos() {
let references = new Map()
let multiples = 0
for (let [url, tiles] of registeredTiles.entries()) {
let count = tiles.size
references.set(url, count)
if (count > 1) {
multiples += 1
}
}
console.log({ multiples, references })
}
}