UNPKG

@pixi/core

Version:
294 lines (291 loc) 9.51 kB
import { Rectangle, Point } from '@pixi/math'; import { settings } from '@pixi/settings'; import { EventEmitter, TextureCache, uid, getResolutionOfUrl } from '@pixi/utils'; import { BaseTexture } from './BaseTexture.mjs'; import { ImageResource } from './resources/ImageResource.mjs'; import { TextureUvs } from './TextureUvs.mjs'; const DEFAULT_UVS = new TextureUvs(); function removeAllHandlers(tex) { tex.destroy = function _emptyDestroy() { }; tex.on = function _emptyOn() { }; tex.once = function _emptyOnce() { }; tex.emit = function _emptyEmit() { }; } class Texture extends EventEmitter { constructor(baseTexture, frame, orig, trim, rotate, anchor, borders) { super(); this.noFrame = false; if (!frame) { this.noFrame = true; frame = new Rectangle(0, 0, 1, 1); } if (baseTexture instanceof Texture) { baseTexture = baseTexture.baseTexture; } this.baseTexture = baseTexture; this._frame = frame; this.trim = trim; this.valid = false; this._uvs = DEFAULT_UVS; this.uvMatrix = null; this.orig = orig || frame; this._rotate = Number(rotate || 0); if (rotate === true) { this._rotate = 2; } else if (this._rotate % 2 !== 0) { throw new Error("attempt to use diamond-shaped UVs. If you are sure, set rotation manually"); } this.defaultAnchor = anchor ? new Point(anchor.x, anchor.y) : new Point(0, 0); this.defaultBorders = borders; this._updateID = 0; this.textureCacheIds = []; if (!baseTexture.valid) { baseTexture.once("loaded", this.onBaseTextureUpdated, this); } else if (this.noFrame) { if (baseTexture.valid) { this.onBaseTextureUpdated(baseTexture); } } else { this.frame = frame; } if (this.noFrame) { baseTexture.on("update", this.onBaseTextureUpdated, this); } } update() { if (this.baseTexture.resource) { this.baseTexture.resource.update(); } } onBaseTextureUpdated(baseTexture) { if (this.noFrame) { if (!this.baseTexture.valid) { return; } this._frame.width = baseTexture.width; this._frame.height = baseTexture.height; this.valid = true; this.updateUvs(); } else { this.frame = this._frame; } this.emit("update", this); } destroy(destroyBase) { if (this.baseTexture) { if (destroyBase) { const { resource } = this.baseTexture; if (resource?.url && TextureCache[resource.url]) { Texture.removeFromCache(resource.url); } this.baseTexture.destroy(); } this.baseTexture.off("loaded", this.onBaseTextureUpdated, this); this.baseTexture.off("update", this.onBaseTextureUpdated, this); this.baseTexture = null; } this._frame = null; this._uvs = null; this.trim = null; this.orig = null; this.valid = false; Texture.removeFromCache(this); this.textureCacheIds = null; } clone() { const clonedFrame = this._frame.clone(); const clonedOrig = this._frame === this.orig ? clonedFrame : this.orig.clone(); const clonedTexture = new Texture(this.baseTexture, !this.noFrame && clonedFrame, clonedOrig, this.trim?.clone(), this.rotate, this.defaultAnchor, this.defaultBorders); if (this.noFrame) { clonedTexture._frame = clonedFrame; } return clonedTexture; } updateUvs() { if (this._uvs === DEFAULT_UVS) { this._uvs = new TextureUvs(); } this._uvs.set(this._frame, this.baseTexture, this.rotate); this._updateID++; } static from(source, options = {}, strict = settings.STRICT_TEXTURE_CACHE) { const isFrame = typeof source === "string"; let cacheId = null; if (isFrame) { cacheId = source; } else if (source instanceof BaseTexture) { if (!source.cacheId) { const prefix = options?.pixiIdPrefix || "pixiid"; source.cacheId = `${prefix}-${uid()}`; BaseTexture.addToCache(source, source.cacheId); } cacheId = source.cacheId; } else { if (!source._pixiId) { const prefix = options?.pixiIdPrefix || "pixiid"; source._pixiId = `${prefix}_${uid()}`; } cacheId = source._pixiId; } let texture = TextureCache[cacheId]; if (isFrame && strict && !texture) { throw new Error(`The cacheId "${cacheId}" does not exist in TextureCache.`); } if (!texture && !(source instanceof BaseTexture)) { if (!options.resolution) { options.resolution = getResolutionOfUrl(source); } texture = new Texture(new BaseTexture(source, options)); texture.baseTexture.cacheId = cacheId; BaseTexture.addToCache(texture.baseTexture, cacheId); Texture.addToCache(texture, cacheId); } else if (!texture && source instanceof BaseTexture) { texture = new Texture(source); Texture.addToCache(texture, cacheId); } return texture; } static fromURL(url, options) { const resourceOptions = Object.assign({ autoLoad: false }, options?.resourceOptions); const texture = Texture.from(url, Object.assign({ resourceOptions }, options), false); const resource = texture.baseTexture.resource; if (texture.baseTexture.valid) { return Promise.resolve(texture); } return resource.load().then(() => Promise.resolve(texture)); } static fromBuffer(buffer, width, height, options) { return new Texture(BaseTexture.fromBuffer(buffer, width, height, options)); } static fromLoader(source, imageUrl, name, options) { const baseTexture = new BaseTexture(source, Object.assign({ scaleMode: BaseTexture.defaultOptions.scaleMode, resolution: getResolutionOfUrl(imageUrl) }, options)); const { resource } = baseTexture; if (resource instanceof ImageResource) { resource.url = imageUrl; } const texture = new Texture(baseTexture); if (!name) { name = imageUrl; } BaseTexture.addToCache(texture.baseTexture, name); Texture.addToCache(texture, name); if (name !== imageUrl) { BaseTexture.addToCache(texture.baseTexture, imageUrl); Texture.addToCache(texture, imageUrl); } if (texture.baseTexture.valid) { return Promise.resolve(texture); } return new Promise((resolve) => { texture.baseTexture.once("loaded", () => resolve(texture)); }); } static addToCache(texture, id) { if (id) { if (!texture.textureCacheIds.includes(id)) { texture.textureCacheIds.push(id); } if (TextureCache[id] && TextureCache[id] !== texture) { console.warn(`Texture added to the cache with an id [${id}] that already had an entry`); } TextureCache[id] = texture; } } static removeFromCache(texture) { if (typeof texture === "string") { const textureFromCache = TextureCache[texture]; if (textureFromCache) { const index = textureFromCache.textureCacheIds.indexOf(texture); if (index > -1) { textureFromCache.textureCacheIds.splice(index, 1); } delete TextureCache[texture]; return textureFromCache; } } else if (texture?.textureCacheIds) { for (let i = 0; i < texture.textureCacheIds.length; ++i) { if (TextureCache[texture.textureCacheIds[i]] === texture) { delete TextureCache[texture.textureCacheIds[i]]; } } texture.textureCacheIds.length = 0; return texture; } return null; } get resolution() { return this.baseTexture.resolution; } get frame() { return this._frame; } set frame(frame) { this._frame = frame; this.noFrame = false; const { x, y, width, height } = frame; const xNotFit = x + width > this.baseTexture.width; const yNotFit = y + height > this.baseTexture.height; if (xNotFit || yNotFit) { const relationship = xNotFit && yNotFit ? "and" : "or"; const errorX = `X: ${x} + ${width} = ${x + width} > ${this.baseTexture.width}`; const errorY = `Y: ${y} + ${height} = ${y + height} > ${this.baseTexture.height}`; throw new Error(`Texture Error: frame does not fit inside the base Texture dimensions: ${errorX} ${relationship} ${errorY}`); } this.valid = width && height && this.baseTexture.valid; if (!this.trim && !this.rotate) { this.orig = frame; } if (this.valid) { this.updateUvs(); } } get rotate() { return this._rotate; } set rotate(rotate) { this._rotate = rotate; if (this.valid) { this.updateUvs(); } } get width() { return this.orig.width; } get height() { return this.orig.height; } castToBaseTexture() { return this.baseTexture; } static get EMPTY() { if (!Texture._EMPTY) { Texture._EMPTY = new Texture(new BaseTexture()); removeAllHandlers(Texture._EMPTY); removeAllHandlers(Texture._EMPTY.baseTexture); } return Texture._EMPTY; } static get WHITE() { if (!Texture._WHITE) { const canvas = settings.ADAPTER.createCanvas(16, 16); const context = canvas.getContext("2d"); canvas.width = 16; canvas.height = 16; context.fillStyle = "white"; context.fillRect(0, 0, 16, 16); Texture._WHITE = new Texture(BaseTexture.from(canvas)); removeAllHandlers(Texture._WHITE); removeAllHandlers(Texture._WHITE.baseTexture); } return Texture._WHITE; } } export { Texture }; //# sourceMappingURL=Texture.mjs.map